<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>Hexo</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description">
<meta property="og:type" content="website">
<meta property="og:title" content="Hexo">
<meta property="og:url" content="http://yoursite.com/page/14/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Hexo">
<meta name="twitter:description">
  
    <link rel="alternative" href="/atom.xml" title="Hexo" type="application/atom+xml">
  
  
    <link rel="icon" href="/favicon.png">
  
  <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  <link rel="stylesheet" href="/css/style.css" type="text/css">
  

</head>
<body>
  <div id="container">
    <div id="wrap">
      <header id="header">
  <div id="banner"></div>
  <div id="header-outer" class="outer">
    <div id="header-title" class="inner">
      <h1 id="logo-wrap">
        <a href="/" id="logo">Hexo</a>
      </h1>
      
    </div>
    <div id="header-inner" class="inner">
      <nav id="main-nav">
        <a id="main-nav-toggle" class="nav-icon"></a>
        
          <a class="main-nav-link" href="/">Home</a>
        
          <a class="main-nav-link" href="/archives">Archives</a>
        
      </nav>
      <nav id="sub-nav">
        
          <a id="nav-rss-link" class="nav-icon" href="/atom.xml" title="RSS Feed"></a>
        
        <a id="nav-search-btn" class="nav-icon" title="Search"></a>
      </nav>
      <div id="search-form-wrap">
        <form action="//google.com/search" method="get" accept-charset="UTF-8" class="search-form"><input type="search" name="q" results="0" class="search-form-input" placeholder="Search"><button type="submit" class="search-form-submit">&#xF002;</button><input type="hidden" name="sitesearch" value="http://yoursite.com"></form>
      </div>
    </div>
  </div>
</header>
      <div class="outer">
        <section id="main">
  
    <article id="post-java/2.AOP系列之AspectJ" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/java/2.AOP系列之AspectJ/" class="article-date">
  <time datetime="2015-12-01T05:21:36.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/java/">java</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/java/2.AOP系列之AspectJ/">AOP系列二之AspectJ</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　</p>
<h2 id="u4F7F_u7528"><a href="#u4F7F_u7528" class="headerlink" title="使用"></a>使用</h2><p>要完成代码通过 AspectJ 编译时织入，通常需要两步：</p>
<ol>
<li>编写aspect文件</li>
<li>使用ajc编译器结合aspect文件对源代码进行编译</li>
</ol>
<p>具体使用可以参考链接：<br><a href="http://opoo.org/aspectj-compile-time-weaving/" target="_blank" rel="external">http://opoo.org/aspectj-compile-time-weaving/</a></p>
<h2 id="u4F18_u70B9"><a href="#u4F18_u70B9" class="headerlink" title="优点"></a>优点</h2><ol>
<li>由于将切面直接编译进了字节码，所以运行时不再需要动态创建代理对象，节约了内存呢和 CPU 消耗；</li>
<li>通过AspectJ，方法被织入了切面后，方法上的 Annotation 还是有效的，因为对象类型没有变。而动态代理可能会以代理类替代原类型，也就失去了 Annotation。</li>
</ol>
<h2 id="u7F3A_u70B9"><a href="#u7F3A_u70B9" class="headerlink" title="缺点"></a>缺点</h2><ol>
<li>编写 aspect 文件有一定的难度；</li>
<li>编译过程稍显复杂（借助工具可简化：Eclipse AJDT, Maven AspectJ 插件等）。<br>只需对便后之后的代码用Intellij IDEA进行查看即可看到效果</li>
</ol>
<h2 id="u7CFB_u5217_u6587_u7AE0"><a href="#u7CFB_u5217_u6587_u7AE0" class="headerlink" title="系列文章"></a>系列文章</h2><p><a href="/../1.AOP系列之概述/">1. AOP系列之概述</a><br><a href="/../2.AOP系列之AspectJ/">2. AOP系列之AspectJ</a><br><a href="/../3.AOP系列之JDK Proxy/">3. AOP系列之JDK Proxy</a><br><a href="/../4.AOP系列之CGLIB/">4. AOP系列之CGLIB</a><br><a href="/../5.AOP系列之CGLIB源码学习/">5. AOP系列之CGLIB源码学习</a><br><a href="/../6.AOP系列之Spring AOP/">6. AOP系列之Spring AOP</a><br><a href="/../7.AOP系列之Spring AspectJ/">7. AOP系列之Spring AspectJ</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/java/2.AOP系列之AspectJ/" data-id="cijzzpvdv00d21cfs1g5d6edx" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/aop/">aop</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/aspectj/">aspectj</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/12.RPC系列之CommonJS服务注册机制" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/12.RPC系列之CommonJS服务注册机制/" class="article-date">
  <time datetime="2015-12-01T04:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/12.RPC系列之CommonJS服务注册机制/">RPC系列十二之CommonJS 服务注册机制</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/12.RPC系列之CommonJS服务注册机制/" data-id="cijzzpv4l00361cfs8ijo0m26" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/commonjs/">commonjs</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/11.RPC系列之CommonJS入门" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/11.RPC系列之CommonJS入门/" class="article-date">
  <time datetime="2015-12-01T03:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/11.RPC系列之CommonJS入门/">RPC系列十一之CommonJS 入门</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　commonrpc是一个以netty传输协议框架为基础，不侵入任何业务代码，支持插件模式，并且即插即用的高性能分布式rpc框架。下面是 CommonRpc 架构图，是不是和dubbo差不多！下面的介绍直接从作者的wiki上直接移过来，没做什么变化<img src="/images/commonrpc.png" alt="commonrpc.png"></p>
<h2 id="CommonRpc__u6D41_u7A0B"><a href="#CommonRpc__u6D41_u7A0B" class="headerlink" title="CommonRpc 流程"></a>CommonRpc 流程</h2><ol>
<li>服务端启动，把服务端对应的服务注册到注册中心</li>
<li>客户端启动，把客户端的IP地址信息注册到注册中心</li>
<li>客户端调用服务端的服务，通过注册中心发现活着的服务，同时记录客户端连接服务端的信息</li>
<li>服务端接受客户端响应，找到对应服务，执行方法，返回给客户端响应结果</li>
</ol>
<h2 id="CommonRpc__u707E_u5907_u5904_u7406"><a href="#CommonRpc__u707E_u5907_u5904_u7406" class="headerlink" title="CommonRpc 灾备处理"></a>CommonRpc 灾备处理</h2><ol>
<li>服务提供者无状态，任意一台宕掉后，不影响使用</li>
<li>注册中心对等集群，任意一台宕掉后，将自动切换到另一台</li>
<li>注册中心全部宕掉后，服务提供者和服务消费者仍能通过本地缓存通讯   </li>
<li>服务提供者全部宕掉后，服务消费者应用将无法使用，并无限次重连等待服务提供者恢复</li>
</ol>
<h2 id="CommonRpc__u4F38_u7F29_u6027"><a href="#CommonRpc__u4F38_u7F29_u6027" class="headerlink" title="CommonRpc 伸缩性"></a>CommonRpc 伸缩性</h2><ol>
<li>注册中心为对等集群，可动态增加机器部署实例，所有客户端将自动发现新的注册中心</li>
<li>服务提供者无状态，可动态增加机器部署实例，注册中心将推送新的服务提供者信息给消费者</li>
</ol>
<h2 id="CommonRpc__u529F_u80FD_u4EE5_u53CA_u7279_u70B9"><a href="#CommonRpc__u529F_u80FD_u4EE5_u53CA_u7279_u70B9" class="headerlink" title="CommonRpc 功能以及特点"></a>CommonRpc 功能以及特点</h2><p>功能如下：<br>　　1. 支持HTTP 协议，TCP 协议<br>　　2. 注册中心支持发现服务，服务治理功能<br>　　3. 管理中心支持通过界面查询服务端以及客户端的状态<br>　　4. 提供服务端拦截器功能<br>　　5. 支持负载均衡，分布式集群功能<br>　　6. 支持流量漂移，降级，限流 可扩展功能<br>　　7. 支持restful模式的http协议,通过配置文件模式,就可以提供HTTP请求<br>特点：插拔模式，配置文件模式，不侵入业务代码</p>
<h2 id="u793A_u4F8B"><a href="#u793A_u4F8B" class="headerlink" title="示例"></a>示例</h2><p>　　在作者的代码中已经提供了比较完备的测试代码，这里直接运行。注意，需要先启动好zookeeper服务端，zookeeper的部署安装和启动方式这里不做介绍！假设运行地址为：localhost:2181</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/11.RPC系列之CommonJS入门/" data-id="cijzzpv4p003b1cfspfxmoach" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/commonjs/">commonjs</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/10.RPC系列之Thrift 异步调用" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/10.RPC系列之Thrift 异步调用/" class="article-date">
  <time datetime="2015-12-01T02:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/10.RPC系列之Thrift 异步调用/">RPC系列十之Thrift 异步调用</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　先占位，待补充<br>``` java</p>
<p><a href="http://www.micmiu.com/soa/rpc/thrift-sample/" target="_blank" rel="external">http://www.micmiu.com/soa/rpc/thrift-sample/</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/10.RPC系列之Thrift 异步调用/" data-id="cijzzpv4y003g1cfs68hvbayx" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/9.RPC系列之Thrift TProcessor源码分析" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/9.RPC系列之Thrift TProcessor源码分析/" class="article-date">
  <time datetime="2015-12-01T01:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/9.RPC系列之Thrift TProcessor源码分析/">RPC系列九之Thrift TProcessor源码分析</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　本篇文章标题不是太准确啊，这里我们会介绍到通过thrift解析器生成的User和HelloWorldService的源码，并结合示例代码进行分析。事实上，每一个生成的HelloWorldService都会有一个TProcessor的实现。首先我们看看生成的User类</p>
<h2 id="User"><a href="#User" class="headerlink" title="User"></a>User</h2><p>　　下面仅仅列出最关键的代码。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">User</span> <span class="keyword">implements</span> <span class="title">org</span>.<span class="title">apache</span>.<span class="title">thrift</span>.<span class="title">TBase</span>&lt;<span class="title">User</span>, <span class="title">User</span>.<span class="title">_Fields</span>&gt;, <span class="title">java</span>.<span class="title">io</span>.<span class="title">Serializable</span>, <span class="title">Cloneable</span>, <span class="title">Comparable</span>&lt;<span class="title">User</span>&gt; </span>&#123;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> org.apache.thrift.protocol.TStruct STRUCT_DESC = <span class="keyword">new</span> org.apache.thrift.protocol.TStruct(<span class="string">"User"</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> org.apache.thrift.protocol.TField TYPE_FIELD_DESC = <span class="keyword">new</span> org.apache.thrift.protocol.TField(<span class="string">"type"</span>, org.apache.thrift.protocol.TType.I32, (<span class="keyword">short</span>)<span class="number">1</span>);</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> org.apache.thrift.protocol.TField NAME_FIELD_DESC = <span class="keyword">new</span> org.apache.thrift.protocol.TField(<span class="string">"name"</span>, org.apache.thrift.protocol.TType.STRING, (<span class="keyword">short</span>)<span class="number">2</span>);</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> org.apache.thrift.protocol.TField SEX_FIELD_DESC = <span class="keyword">new</span> org.apache.thrift.protocol.TField(<span class="string">"sex"</span>, org.apache.thrift.protocol.TType.STRING, (<span class="keyword">short</span>)<span class="number">3</span>);</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> org.apache.thrift.protocol.TField SCHOOL_FIELD_DESC = <span class="keyword">new</span> org.apache.thrift.protocol.TField(<span class="string">"school"</span>, org.apache.thrift.protocol.TType.STRING, (<span class="keyword">short</span>)<span class="number">4</span>);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Map&lt;Class&lt;? extends IScheme&gt;, SchemeFactory&gt; schemes = <span class="keyword">new</span> HashMap&lt;Class&lt;? extends IScheme&gt;, SchemeFactory&gt;();</span><br><span class="line">  <span class="keyword">static</span> &#123;</span><br><span class="line">    schemes.put(StandardScheme.class, <span class="keyword">new</span> UserStandardSchemeFactory());</span><br><span class="line">    schemes.put(TupleScheme.class, <span class="keyword">new</span> UserTupleSchemeFactory());</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">int</span> type; <span class="comment">// required</span></span><br><span class="line">  <span class="keyword">public</span> String name; <span class="comment">// optional</span></span><br><span class="line">  <span class="keyword">public</span> String sex; <span class="comment">// optional</span></span><br><span class="line">  <span class="keyword">public</span> String school; <span class="comment">// optional</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">enum</span> _Fields implements org.apache.thrift.TFieldIdEnum &#123;</span><br><span class="line">    TYPE((<span class="keyword">short</span>)<span class="number">1</span>, <span class="string">"type"</span>),</span><br><span class="line">    NAME((<span class="keyword">short</span>)<span class="number">2</span>, <span class="string">"name"</span>),</span><br><span class="line">    SEX((<span class="keyword">short</span>)<span class="number">3</span>, <span class="string">"sex"</span>),</span><br><span class="line">    SCHOOL((<span class="keyword">short</span>)<span class="number">4</span>, <span class="string">"school"</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Map&lt;String, _Fields&gt; byName = <span class="keyword">new</span> HashMap&lt;String, _Fields&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">static</span> &#123;</span><br><span class="line">      <span class="keyword">for</span> (_Fields field : EnumSet.allOf(_Fields.class)) &#123;</span><br><span class="line">        byName.put(field.getFieldName(), field);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> _Fields <span class="title">findByThriftId</span><span class="params">(<span class="keyword">int</span> fieldId)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">switch</span>(fieldId) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">1</span>: <span class="comment">// TYPE</span></span><br><span class="line">          <span class="keyword">return</span> TYPE;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">2</span>: <span class="comment">// NAME</span></span><br><span class="line">          <span class="keyword">return</span> NAME;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">3</span>: <span class="comment">// SEX</span></span><br><span class="line">          <span class="keyword">return</span> SEX;</span><br><span class="line">        <span class="keyword">case</span> <span class="number">4</span>: <span class="comment">// SCHOOL</span></span><br><span class="line">          <span class="keyword">return</span> SCHOOL;</span><br><span class="line">        <span class="keyword">default</span>:</span><br><span class="line">          <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">//findByThriftIdOrThrow findByName等方法</span></span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> <span class="keyword">short</span> _thriftId;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> String _fieldName;</span><br><span class="line"></span><br><span class="line">    _Fields(<span class="keyword">short</span> thriftId, String fieldName) &#123;</span><br><span class="line">      _thriftId = thriftId;</span><br><span class="line">      _fieldName = fieldName;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// isset id assignments</span></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> __TYPE_ISSET_ID = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">byte</span> __isset_bitfield = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> _Fields optionals[] = &#123;_Fields.NAME,_Fields.SEX,_Fields.SCHOOL&#125;;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Map&lt;_Fields, org.apache.thrift.meta_data.FieldMetaData&gt; metaDataMap;</span><br><span class="line">  <span class="keyword">static</span> &#123;</span><br><span class="line">    Map&lt;_Fields, org.apache.thrift.meta_data.FieldMetaData&gt; tmpMap = <span class="keyword">new</span> EnumMap&lt;_Fields, org.apache.thrift.meta_data.FieldMetaData&gt;(_Fields.class);</span><br><span class="line">    tmpMap.put(_Fields.TYPE, <span class="keyword">new</span> org.apache.thrift.meta_data.FieldMetaData(<span class="string">"type"</span>, org.apache.thrift.TFieldRequirementType.REQUIRED, </span><br><span class="line">        <span class="keyword">new</span> org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.I32)));</span><br><span class="line">    tmpMap.put(_Fields.NAME, <span class="keyword">new</span> org.apache.thrift.meta_data.FieldMetaData(<span class="string">"name"</span>, org.apache.thrift.TFieldRequirementType.OPTIONAL, </span><br><span class="line">        <span class="keyword">new</span> org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));</span><br><span class="line">    tmpMap.put(_Fields.SEX, <span class="keyword">new</span> org.apache.thrift.meta_data.FieldMetaData(<span class="string">"sex"</span>, org.apache.thrift.TFieldRequirementType.OPTIONAL, </span><br><span class="line">        <span class="keyword">new</span> org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));</span><br><span class="line">    tmpMap.put(_Fields.SCHOOL, <span class="keyword">new</span> org.apache.thrift.meta_data.FieldMetaData(<span class="string">"school"</span>, org.apache.thrift.TFieldRequirementType.OPTIONAL, </span><br><span class="line">        <span class="keyword">new</span> org.apache.thrift.meta_data.FieldValueMetaData(org.apache.thrift.protocol.TType.STRING)));</span><br><span class="line">    metaDataMap = Collections.unmodifiableMap(tmpMap);</span><br><span class="line">    org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(User.class, metaDataMap);</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">//type等属性对应的unset set get方法 </span></span><br><span class="line">  </span><br><span class="line">  <span class="function"><span class="keyword">public</span> _Fields <span class="title">fieldForId</span><span class="params">(<span class="keyword">int</span> fieldId)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> _Fields.findByThriftId(fieldId);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(org.apache.thrift.protocol.TProtocol iprot)</span> <span class="keyword">throws</span> org.apache.thrift.TException </span>&#123;</span><br><span class="line">    schemes.get(iprot.getScheme()).getScheme().read(iprot, <span class="keyword">this</span>);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(org.apache.thrift.protocol.TProtocol oprot)</span> <span class="keyword">throws</span> org.apache.thrift.TException </span>&#123;</span><br><span class="line">    schemes.get(oprot.getScheme()).getScheme().write(oprot, <span class="keyword">this</span>);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">writeObject</span><span class="params">(java.io.ObjectOutputStream out)</span> <span class="keyword">throws</span> java.io.IOException </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      write(<span class="keyword">new</span> org.apache.thrift.protocol.TCompactProtocol(<span class="keyword">new</span> org.apache.thrift.transport.TIOStreamTransport(out)));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (org.apache.thrift.TException te) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> java.io.IOException(te);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">readObject</span><span class="params">(java.io.ObjectInputStream in)</span> <span class="keyword">throws</span> java.io.IOException, ClassNotFoundException </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="comment">// it doesn't seem like you should have to do this, but java serialization is wacky, and doesn't call the default constructor.</span></span><br><span class="line">      __isset_bitfield = <span class="number">0</span>;</span><br><span class="line">      read(<span class="keyword">new</span> org.apache.thrift.protocol.TCompactProtocol(<span class="keyword">new</span> org.apache.thrift.transport.TIOStreamTransport(in)));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (org.apache.thrift.TException te) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> java.io.IOException(te);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">UserStandardSchemeFactory</span> <span class="keyword">implements</span> <span class="title">SchemeFactory</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> UserStandardScheme <span class="title">getScheme</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> UserStandardScheme();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">UserStandardScheme</span> <span class="keyword">extends</span> <span class="title">StandardScheme</span>&lt;<span class="title">User</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(org.apache.thrift.protocol.TProtocol iprot, User struct)</span> <span class="keyword">throws</span> org.apache.thrift.TException </span>&#123;</span><br><span class="line">      <span class="comment">//反序列化，根据读取到的字段id号，进行匹配</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(org.apache.thrift.protocol.TProtocol oprot, User struct)</span> <span class="keyword">throws</span> org.apache.thrift.TException </span>&#123;</span><br><span class="line">      <span class="comment">//非tuple协议的，均在此处序列化User，这里实际上设置的为序列化后字段对应的id号</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">UserTupleSchemeFactory</span> <span class="keyword">implements</span> <span class="title">SchemeFactory</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> UserTupleScheme <span class="title">getScheme</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> UserTupleScheme();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">UserTupleScheme</span> <span class="keyword">extends</span> <span class="title">TupleScheme</span>&lt;<span class="title">User</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(org.apache.thrift.protocol.TProtocol prot, User struct)</span> <span class="keyword">throws</span> org.apache.thrift.TException </span>&#123;</span><br><span class="line">      <span class="comment">//以tuple的格式进行序列化</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(org.apache.thrift.protocol.TProtocol prot, User struct)</span> <span class="keyword">throws</span> org.apache.thrift.TException </span>&#123;</span><br><span class="line">      <span class="comment">//将tuple格式的数据反序列化成User</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　首先在User中最基础的便是TField类型的变量，每个属性（如name、sex等）都各自对应一个TField类型的static final属性，TField包含了该属性的名称，字段类型和属性id号。如type属性对应的Field如下（精简了包名）：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> TField TYPE_FIELD_DESC = <span class="keyword">new</span> TField(<span class="string">"type"</span>, TType.I32, (<span class="keyword">short</span>)<span class="number">1</span>);</span><br></pre></td></tr></table></figure></p>
<p>　　在User中还包含了一个静态代码块，会将user的元数据信息注册到org.apache.thrift.meta_data.FieldMetaData中，暂时没发现有地方使用过。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> Map&lt;_Fields, org.apache.thrift.meta_data.FieldMetaData&gt; metaDataMap;</span><br><span class="line"><span class="keyword">static</span> &#123;</span><br><span class="line">  Map&lt;_Fields, FieldMetaData&gt; tmpMap = <span class="keyword">new</span> EnumMap&lt;_Fields, FieldMetaData&gt;(_Fields.class);</span><br><span class="line">  tmpMap.put(_Fields.TYPE, FieldMetaData(<span class="string">"type"</span>, TFieldRequirementType.REQUIRED, <span class="keyword">new</span> FieldValueMetaData(TType.I32)));</span><br><span class="line">  <span class="comment">//在放入其它的属性，如sex, name等。</span></span><br><span class="line">  org.apache.thrift.meta_data.FieldMetaData.addStructMetaDataMap(User.class, metaDataMap);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　还有一个内部枚举类_Fields，该枚举实现了接口TFieldIdEnum，每个枚举类型则包括了字段的id号和字段名称。最后也是最重要的便是对StandardScheme和TupleScheme的实现，他们定义了User类的序列化方式方式，详见上一篇文章介绍。</p>
<h2 id="HelloWorldService"><a href="#HelloWorldService" class="headerlink" title="HelloWorldService"></a>HelloWorldService</h2><p>　　下面我们进入HelloWorldService2的源码，梳理一下thrift为我们生成的HelloWorldService2的代码结构。首先可看接口的定义Iface和AsyncIface以及客户端涉及的代码Client和AsyncClient！<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloWorldService2</span> </span>&#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Iface</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">sayHello</span><span class="params">(String name)</span> <span class="keyword">throws</span> TException</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">AsyncIface</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sayHello</span><span class="params">(String name, AsyncMethodCallback resultHandler)</span> <span class="keyword">throws</span> TException</span>;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> <span class="keyword">extends</span> <span class="title">TServiceClient</span> <span class="keyword">implements</span> <span class="title">Iface</span> </span>&#123;</span><br><span class="line">    <span class="comment">//省略构造方法和工厂类</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">sayHello</span><span class="params">(String name)</span> <span class="keyword">throws</span> TException</span>&#123;</span><br><span class="line">      send_sayHello(name);</span><br><span class="line">      <span class="keyword">return</span> recv_sayHello();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">send_sayHello</span><span class="params">(String name)</span> <span class="keyword">throws</span> TException</span>&#123;</span><br><span class="line">      sayHello_args args = <span class="keyword">new</span> sayHello_args();</span><br><span class="line">      args.setName(name);</span><br><span class="line">      sendBase(<span class="string">"sayHello"</span>, args);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">recv_sayHello</span><span class="params">()</span> <span class="keyword">throws</span> TException </span>&#123;</span><br><span class="line">      sayHello_result result = <span class="keyword">new</span> sayHello_result();</span><br><span class="line">      receiveBase(result, <span class="string">"sayHello"</span>);</span><br><span class="line">      <span class="keyword">if</span> (result.isSetSuccess()) &#123;</span><br><span class="line">        <span class="keyword">return</span> result.success;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">AsyncClient</span> <span class="keyword">extends</span> <span class="title">TAsyncClient</span> <span class="keyword">implements</span> <span class="title">AsyncIface</span> </span>&#123;</span><br><span class="line">    <span class="comment">//省略构造方法和工厂类</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">sayHello</span><span class="params">(String name, AsyncMethodCallback resultHandler)</span> <span class="keyword">throws</span> TException </span>&#123;</span><br><span class="line">      checkReady();</span><br><span class="line">      sayHello_call method_call = <span class="keyword">new</span> sayHello_call(name, resultHandler, <span class="keyword">this</span>, ___protocolFactory, ___transport);</span><br><span class="line">      <span class="keyword">this</span>.___currentMethod = method_call;</span><br><span class="line">      ___manager.call(method_call);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">sayHello_call</span> <span class="keyword">extends</span> <span class="title">TAsyncMethodCall</span> </span>&#123;</span><br><span class="line">      <span class="keyword">private</span> String name;</span><br><span class="line">      <span class="function"><span class="keyword">public</span> <span class="title">sayHello_call</span><span class="params">(String name, AsyncMethodCallback resultHandler, TAsyncClient client, TProtocolFactory protocolFactory, TNonblockingTransport transport)</span> <span class="keyword">throws</span> TException </span>&#123;</span><br><span class="line">        <span class="keyword">super</span>(client, protocolFactory, transport, resultHandler, <span class="keyword">false</span>);</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write_args</span><span class="params">(TProtocol prot)</span> <span class="keyword">throws</span> TException </span>&#123;</span><br><span class="line">        prot.writeMessageBegin(<span class="keyword">new</span> TMessage(<span class="string">"sayHello"</span>, TMessageType.CALL, <span class="number">0</span>));</span><br><span class="line">        sayHello_args args = <span class="keyword">new</span> sayHello_args();</span><br><span class="line">        args.setName(name);</span><br><span class="line">        args.write(prot);</span><br><span class="line">        prot.writeMessageEnd();</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="function"><span class="keyword">public</span> String <span class="title">getResult</span><span class="params">()</span> <span class="keyword">throws</span> TException </span>&#123;</span><br><span class="line">        TMemoryInputTransport memoryTransport = <span class="keyword">new</span> TMemoryInputTransport(getFrameBuffer().array());</span><br><span class="line">        TProtocol prot = client.getProtocolFactory().getProtocol(memoryTransport);</span><br><span class="line">        <span class="keyword">return</span> (<span class="keyword">new</span> Client(prot)).recv_sayHello();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　thrift为定义了HelloWorldService2两组接口：Iface、AsyncIface和Client、AsyncClient。其中Iface、AsyncIface定义了服务的接口sayHello，Client和AsyncClient则用于客户端的代码调用。其中Client方法最终会调用父类TServiceClient的sendBase方法，将请求进行序列化，写入流中。<br>　　服务端收到消息后，将请求交由HelloWorldService2的两个内部类Processor和AsyncProcessor执行，顾名思义，一个是同步调用，一个是异步调用<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Processor</span>&lt;<span class="title">I</span> <span class="keyword">extends</span> <span class="title">Iface</span>&gt; <span class="keyword">extends</span> <span class="title">TBaseProcessor</span>&lt;<span class="title">I</span>&gt; <span class="keyword">implements</span> <span class="title">TProcessor</span> </span>&#123;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger LOGGER = LoggerFactory.getLogger(Processor.class.getName());</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">Processor</span><span class="params">(I iface)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(iface, getProcessMap(<span class="keyword">new</span> HashMap&lt;String, org.apache.thrift.ProcessFunction&lt;I, ? extends org.apache.thrift.TBase&gt;&gt;()));</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> &lt;I extends Iface&gt; Map&lt;String, ProcessFunction&lt;I, ? extends TBase&gt;&gt; getProcessMap(Map&lt;String, ProcessFunction&lt;I, ? extends  TBase&gt;&gt; processMap) &#123;</span><br><span class="line">    processMap.put(<span class="string">"sayHello"</span>, <span class="keyword">new</span> sayHello());</span><br><span class="line">    <span class="keyword">return</span> processMap;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">sayHello</span>&lt;<span class="title">I</span> <span class="keyword">extends</span> <span class="title">Iface</span>&gt; <span class="keyword">extends</span> <span class="title">ProcessFunction</span>&lt;<span class="title">I</span>, <span class="title">sayHello_args</span>&gt; </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">sayHello</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>(<span class="string">"sayHello"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> sayHello_result <span class="title">getResult</span><span class="params">(I iface, sayHello_args args)</span> <span class="keyword">throws</span> TException </span>&#123;</span><br><span class="line">      sayHello_result result = <span class="keyword">new</span> sayHello_result();</span><br><span class="line">      result.success = iface.sayHello(args.name);</span><br><span class="line">      <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　这里有一个非常巧妙的实现，在Processor内部类中存在一个名为sayHello的内部类，同时通过Processor.getProcessMap方法将名为sayHello的方法与名为sayHello的内部类建立了映射关系（放入了hashMap）。<br>　　当服务端获取到客户端调用sayhello方法的消息后，直接到hashMap中根据key=sayHello可以找到对应的value=sayHello内部类，并统一执行该内部类的getResult方法，而getResult方法又调用了Processor成员变量iface的sayHello方法。该成员变量在构造Processor对象是初始化。如下所示服务端的TProcessor初始化代码：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">TProcessor tprocessor = <span class="keyword">new</span> HelloWorldService2.Processor&lt;HelloWorldService2.Iface&gt;(<span class="keyword">new</span> HelloWorldImpl2());</span><br></pre></td></tr></table></figure></p>
<p>　　通过这种方式，thrift规避了采用反射的方式执行，毕竟反射性能或多或少比直接调用的慢一点吧，神实现！！！最后我们简单了解一下AsyncProcessor的实现原理<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">AsyncProcessor</span>&lt;<span class="title">I</span> <span class="keyword">extends</span> <span class="title">AsyncIface</span>&gt; <span class="keyword">extends</span> <span class="title">TBaseAsyncProcessor</span>&lt;<span class="title">I</span>&gt; </span>&#123;</span><br><span class="line">  </span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">AsyncProcessor</span><span class="params">(I iface)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(iface, getProcessMap(<span class="keyword">new</span> HashMap&lt;String, org.apache.thrift.AsyncProcessFunction&lt;I, ? extends org.apache.thrift.TBase, ?&gt;&gt;()));</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">static</span> &lt;I extends AsyncIface&gt; Map&lt;String, AsyncProcessFunction&lt;I, ? extends TBase,?&gt;&gt; getProcessMap(Map&lt;String, AsyncProcessFunction&lt;I, ? extends TBase, ?&gt;&gt; processMap) &#123;</span><br><span class="line">    processMap.put(<span class="string">"sayHello"</span>, <span class="keyword">new</span> sayHello());</span><br><span class="line">    <span class="keyword">return</span> processMap;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">sayHello</span>&lt;<span class="title">I</span> <span class="keyword">extends</span> <span class="title">AsyncIface</span>&gt; <span class="keyword">extends</span> <span class="title">org</span>.<span class="title">apache</span>.<span class="title">thrift</span>.<span class="title">AsyncProcessFunction</span>&lt;<span class="title">I</span>, <span class="title">sayHello_args</span>, <span class="title">String</span>&gt; </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">sayHello</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>(<span class="string">"sayHello"</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> AsyncMethodCallback&lt;String&gt; <span class="title">getResultHandler</span><span class="params">(<span class="keyword">final</span> AsyncFrameBuffer fb, <span class="keyword">final</span> <span class="keyword">int</span> seqid)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">final</span> org.apache.thrift.AsyncProcessFunction fcall = <span class="keyword">this</span>;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">new</span> AsyncMethodCallback&lt;String&gt;() &#123; </span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onComplete</span><span class="params">(String o)</span> </span>&#123;</span><br><span class="line">          sayHello_result result = <span class="keyword">new</span> sayHello_result();</span><br><span class="line">          result.success = o;</span><br><span class="line">          <span class="keyword">try</span> &#123;</span><br><span class="line">            fcall.sendResponse(fb,result, org.apache.thrift.protocol.TMessageType.REPLY,seqid);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">          &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            LOGGER.error(<span class="string">"Exception writing to internal frame buffer"</span>, e);</span><br><span class="line">          &#125;</span><br><span class="line">          fb.close();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onError</span><span class="params">(Exception e)</span> </span>&#123;</span><br><span class="line">          <span class="keyword">byte</span> msgType = org.apache.thrift.protocol.TMessageType.REPLY;</span><br><span class="line">          org.apache.thrift.TBase msg;</span><br><span class="line">          sayHello_result result = <span class="keyword">new</span> sayHello_result();</span><br><span class="line">          &#123;</span><br><span class="line">            msgType = org.apache.thrift.protocol.TMessageType.EXCEPTION;</span><br><span class="line">            msg = (org.apache.thrift.TBase)<span class="keyword">new</span> org.apache.thrift.TApplicationException(org.apache.thrift.TApplicationException.INTERNAL_ERROR, e.getMessage());</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">try</span> &#123;</span><br><span class="line">            fcall.sendResponse(fb,msg,msgType,seqid);</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">          &#125; <span class="keyword">catch</span> (Exception ex) &#123;</span><br><span class="line">            LOGGER.error(<span class="string">"Exception writing to internal frame buffer"</span>, ex);</span><br><span class="line">          &#125;</span><br><span class="line">          fb.close();</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">start</span><span class="params">(I iface, sayHello_args args, org.apache.thrift.async.AsyncMethodCallback&lt;String&gt; resultHandler)</span> <span class="keyword">throws</span> TException </span>&#123;</span><br><span class="line">      iface.sayHello(args.name,resultHandler);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　与同步AsyncProcessor执行getResult不同，AsyncMethodCallback执行的是start方法，在该方法中调用服务接口的对应方法，同时通过回调接口AsyncMethodCallback实现执行结果的异步返回。这里有一个细节需要注意：每次接口调用，都会带上seqid作为该次请求的唯一标识（自增形式），返回结果时也带上该值作为标识，匹配对应的请求。</p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　其实，TProcessor的实现原理主要在thrift为我们生成的服务类HelloWorldService中，理清了HelloWorldService的结构原理基本就OK了。再次强调一次，服务端接口的执行并不是采用反射的形式哦。<br>　　到这里Thrift就介绍完毕了。有几点需要注意的是：<br>　　1. thrift提供了与hessian类型的基于http的rpc调用，采用org.apache.thrift.server.TServlet和org.apache.thrift.transport.THttpClient搭配即可<br>　　2. thrift不支持接口的重载。<br>　　3. 提供了多种序列化方式和服务端实现，以及同步异步的调用</p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/9.RPC系列之Thrift TProcessor源码分析/" data-id="cijzzpv2i001r1cfslat98eo0" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/8.RPC系列之Thrift TServer源码分析" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/8.RPC系列之Thrift TServer源码分析/" class="article-date">
  <time datetime="2015-12-01T00:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/8.RPC系列之Thrift TServer源码分析/">RPC系列八之Thrift TServer源码分析</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　作为一个高性能RPC框架，还需要一个Server层，用于从Transport接收序列化的消息，再根据protocol反序列化并调用用户定义的消息处理器，然后序列化消息处理器的响应，最后再将它们写回Transport。Thrift模块化的结构使得它能提供各种Server实现。下面列出了Java中可用的TServer实现：<br>　　1. <strong>TSimpleServer</strong>：它接受一个连接，处理连接请求，直到客户端关闭了连接，它才会去接受一个新的连接。正因为它只在一个单独的线程中以阻塞I/O的方式完成这些工作，所以它只能服务一个客户端连接，其他所有客户端在被服务器端接受之前都只能等待。TSimpleServer主要用于测试目的，不要在生产环境中使用它！<br>　　2. <strong>TNonblockingServer</strong>：使用NIO解决了TSimpleServer一个客户端阻塞其他所有客户端的问题。它通过使用java.nio.channels.Selector的select()方法，使得你阻塞在多个连接上，而不是阻塞在单一的连接上。当一或多个连接准备好被接受/读/写时，select()调用便会返回。TNonblockingServer处理这些连接的时候，要么接受它，要么从它那读数据，要么把数据写到它那里，然后再次调用select()来等待下一个可用的连接。通用这种方式，server可同时服务多个客户端。但是这样有一个问题：<strong>所有消息是被调用select()方法的同一个线程处理的（循环调用SelectionKey集合，按顺序逐一处理每一个消息）</strong>。假设有10个客户端，处理每条消息所需时间为100毫秒，那么，latency和吞吐量分别是多少？当一条消息被处理的时候，其他9个客户端就等着被select，所以客户端需要等待1秒钟才能从服务器端得到回应，吞吐量就是10个请求/秒。简单点就是：<strong>一个线程处理所有的io和业务代码执行</strong><br>　　3. <strong>THsHaServer</strong>：为了解决TNonblockingServer的问题（一个时间只能处理一条消息），THsHaServer（半同步/半异步的server）就应运而生了。它使用<strong>一个单独的线程来处理网络I/O，一个独立的worker线程池来处理消息</strong>。这样，只要有空闲的worker线程，消息就会被立即处理，因此多条消息能被并行处理。用上面的例子来说，现在的latency就是100毫秒，而吞吐量就是100个请求/秒（按10个客户端计算）。<br>　　4. <strong>TThreadedSelectorServer</strong>：它与THsHaServer的主要区别在于，TThreadedSelectorServer允许你用多个线程来处理网络I/O。它维护了<strong>两个线程池，一个用来处理网络I/O，另一个用来进行请求的处理</strong>。当网络I/O是瓶颈的时候，TThreadedSelectorServer比THsHaServer的表现要好。<br>　　5. <strong>TThreadPoolServer</strong>：有一个专用的线程用来接受连接，一旦接受了一个连接，它就会被放入ThreadPoolExecutor中的一个worker线程里处理io读写和业务代码执行，worker线程被绑定到特定的客户端连接上，直到它关闭。这意味着，如果有1万个并发的客户端连接，你就需要运行1万个线程。所以它对系统资源的消耗不像其他类型的server一样那么友好。此外，如果客户端数量超过了线程池中的最大线程数，在有一个worker线程可用之前，请求将被一直阻塞在那里。<br>　　下面我将逐一进入各个类，理解其实现原理，印证上面每个类的分析结果。</p>
<h2 id="TServer"><a href="#TServer" class="headerlink" title="TServer"></a>TServer</h2><p>　　首先我们看看TServer抽象类，其定义了Server的标准接口。同时，其静态内部类Args和AbstractServerArgs可以理解为java中构造者模式（Builder）的一种使用，这里不做过多的介绍！<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">TServer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Args</span> <span class="keyword">extends</span> <span class="title">AbstractServerArgs</span>&lt;<span class="title">Args</span>&gt; </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Args</span><span class="params">(TServerTransport transport)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>(transport);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractServerArgs</span>&lt;<span class="title">T</span> <span class="keyword">extends</span> <span class="title">AbstractServerArgs</span>&lt;<span class="title">T</span>&gt;&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">final</span> TServerTransport serverTransport;</span><br><span class="line">    TProcessorFactory processorFactory;</span><br><span class="line">    TTransportFactory inputTransportFactory = <span class="keyword">new</span> TTransportFactory();</span><br><span class="line">    TTransportFactory outputTransportFactory = <span class="keyword">new</span> TTransportFactory();</span><br><span class="line">    TProtocolFactory inputProtocolFactory = <span class="keyword">new</span> TBinaryProtocol.Factory();</span><br><span class="line">    TProtocolFactory outputProtocolFactory = <span class="keyword">new</span> TBinaryProtocol.Factory();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AbstractServerArgs</span><span class="params">(TServerTransport transport)</span> </span>&#123;</span><br><span class="line">      serverTransport = transport;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> T <span class="title">processorFactory</span><span class="params">(TProcessorFactory factory)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.processorFactory = factory;</span><br><span class="line">      <span class="keyword">return</span> (T) <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> T <span class="title">processor</span><span class="params">(TProcessor processor)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.processorFactory = <span class="keyword">new</span> TProcessorFactory(processor);</span><br><span class="line">      <span class="keyword">return</span> (T) <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> T <span class="title">transportFactory</span><span class="params">(TTransportFactory factory)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.inputTransportFactory = factory;</span><br><span class="line">      <span class="keyword">this</span>.outputTransportFactory = factory;</span><br><span class="line">      <span class="keyword">return</span> (T) <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//初始化各种factory</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TProcessorFactory processorFactory_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TServerTransport serverTransport_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TTransportFactory inputTransportFactory_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TTransportFactory outputTransportFactory_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TProtocolFactory inputProtocolFactory_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TProtocolFactory outputProtocolFactory_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">boolean</span> isServing;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> TServerEventHandler eventHandler_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> <span class="keyword">volatile</span> <span class="keyword">boolean</span> stopped_ = <span class="keyword">false</span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="title">TServer</span><span class="params">(AbstractServerArgs args)</span> </span>&#123;</span><br><span class="line">    processorFactory_ = args.processorFactory;</span><br><span class="line">    serverTransport_ = args.serverTransport;</span><br><span class="line">    inputTransportFactory_ = args.inputTransportFactory;</span><br><span class="line">    outputTransportFactory_ = args.outputTransportFactory;</span><br><span class="line">    inputProtocolFactory_ = args.inputProtocolFactory;</span><br><span class="line">    outputProtocolFactory_ = args.outputProtocolFactory;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">serve</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//省略其他方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　我们可以看到，其成员变量serverTransport_、inputTransportFactory_、outputTransportFactory_、inputProtocolFactory_和outputProtocolFactory_等。这说明了TServer就是一个大管理，负责协调thrift的各个组件的正常工作，其最重要的一个方法便是抽象方法：serve。下面我们进入TSimpleServer看看其实现</p>
<h2 id="TSimpleServer"><a href="#TSimpleServer" class="headerlink" title="TSimpleServer"></a>TSimpleServer</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TSimpleServer</span> <span class="keyword">extends</span> <span class="title">TServer</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">serve</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">//省略部分代码</span></span><br><span class="line">	......</span><br><span class="line">    <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">      TTransport client = <span class="keyword">null</span>;</span><br><span class="line">      TProcessor processor = <span class="keyword">null</span>;</span><br><span class="line">      TTransport inputTransport = <span class="keyword">null</span>;</span><br><span class="line">      TTransport outputTransport = <span class="keyword">null</span>;</span><br><span class="line">      TProtocol inputProtocol = <span class="keyword">null</span>;</span><br><span class="line">      TProtocol outputProtocol = <span class="keyword">null</span>;</span><br><span class="line">      ServerContext connectionContext = <span class="keyword">null</span>;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        client = serverTransport_.accept();</span><br><span class="line">        <span class="keyword">if</span> (client != <span class="keyword">null</span>) &#123;</span><br><span class="line">          processor = processorFactory_.getProcessor(client);</span><br><span class="line">          inputTransport = inputTransportFactory_.getTransport(client);</span><br><span class="line">          outputTransport = outputTransportFactory_.getTransport(client);</span><br><span class="line">          inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);</span><br><span class="line">          outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);</span><br><span class="line">          <span class="keyword">if</span> (eventHandler_ != <span class="keyword">null</span>) &#123;</span><br><span class="line">            connectionContext = eventHandler_.createContext(inputProtocol, outputProtocol);</span><br><span class="line">          &#125;</span><br><span class="line">          <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">            <span class="keyword">if</span>(!processor.process(inputProtocol, outputProtocol)) &#123;</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (Exception x) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!stopped_) &#123;</span><br><span class="line">          LOGGER.error(<span class="string">"Error occurred during processing of message."</span>, x);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="comment">//省略部分代码</span></span><br><span class="line">      ......</span><br><span class="line">    &#125;</span><br><span class="line">    setServing(<span class="keyword">false</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　TSimpleServer中最重要的代码则是while循环中的 client = serverTransport_.accept();，它会一直阻塞在此处，直到有客户端的连接（TServerTransport为TServerSocket，阻塞式IO实现）才返回。最后在同一个线程的while代码块中调用TProcessor.process方法。正常情况下，该逻辑导致serverTransport_.accept方法只会调用一次，即只能正常处理第一个客户端的连接和消息。如果process方法处理非常耗时，则会影响该客户端的后续消息请求，所以他只适合采用测试环境使用。</p>
<h2 id="TThreadPoolServer"><a href="#TThreadPoolServer" class="headerlink" title="TThreadPoolServer"></a>TThreadPoolServer</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TThreadPoolServer</span> <span class="keyword">extends</span> <span class="title">TServer</span> </span>&#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Args</span> <span class="keyword">extends</span> <span class="title">AbstractServerArgs</span>&lt;<span class="title">Args</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> minWorkerThreads = <span class="number">5</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> maxWorkerThreads = Integer.MAX_VALUE;</span><br><span class="line">    <span class="comment">//其他属性省略</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Args</span><span class="params">(TServerTransport transport)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>(transport);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Args <span class="title">minWorkerThreads</span><span class="params">(<span class="keyword">int</span> n)</span> </span>&#123;</span><br><span class="line">      minWorkerThreads = n;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//其他参数设置方法</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//其他属性省略</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">TThreadPoolServer</span><span class="params">(Args args)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(args);</span><br><span class="line">    <span class="comment">//属性初始化省略</span></span><br><span class="line">    beBackoffSlotInMillis = args.beBackoffSlotLengthUnit.toMillis(args.beBackoffSlotLength);</span><br><span class="line"></span><br><span class="line">    executorService_ = args.executorService != <span class="keyword">null</span> ?</span><br><span class="line">        args.executorService : createDefaultExecutorService(args);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//创建默认的线程池</span></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> ExecutorService <span class="title">createDefaultExecutorService</span><span class="params">(Args args)</span> </span>&#123;</span><br><span class="line">    SynchronousQueue&lt;Runnable&gt; executorQueue =</span><br><span class="line">      <span class="keyword">new</span> SynchronousQueue&lt;Runnable&gt;();</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ThreadPoolExecutor(args.minWorkerThreads,</span><br><span class="line">                                  args.maxWorkerThreads,</span><br><span class="line">                                  args.stopTimeoutVal,</span><br><span class="line">                                  TimeUnit.SECONDS,</span><br><span class="line">                                  executorQueue);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">serve</span><span class="params">()</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">int</span> failureCount = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        TTransport client = serverTransport_.accept();</span><br><span class="line">		<span class="comment">//将新的连接client放到WorkerProcess中，</span></span><br><span class="line">        WorkerProcess wp = <span class="keyword">new</span> WorkerProcess(client);</span><br><span class="line"></span><br><span class="line">        <span class="keyword">int</span> retryCount = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">long</span> remainTimeInMillis = requestTimeoutUnit.toMillis(requestTimeout);</span><br><span class="line">        <span class="keyword">while</span>(<span class="keyword">true</span>) &#123;</span><br><span class="line">          <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="comment">//放入线程池中执行</span></span><br><span class="line">            executorService_.execute(wp);</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">          &#125; <span class="keyword">catch</span>(Throwable t) &#123;</span><br><span class="line">            <span class="comment">//错误处理代码</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (TTransportException ttx) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!stopped_) &#123;</span><br><span class="line">          ++failureCount;</span><br><span class="line">          LOGGER.warn(<span class="string">"Transport error occurred during acceptance of message."</span>, ttx);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	<span class="comment">//处理线程池的关闭</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//内部类，客户端新连接处理线程</span></span><br><span class="line">  <span class="keyword">private</span> <span class="class"><span class="keyword">class</span> <span class="title">WorkerProcess</span> <span class="keyword">implements</span> <span class="title">Runnable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      TProcessor processor = <span class="keyword">null</span>;</span><br><span class="line">      TTransport inputTransport = <span class="keyword">null</span>;</span><br><span class="line">      TTransport outputTransport = <span class="keyword">null</span>;</span><br><span class="line">      TProtocol inputProtocol = <span class="keyword">null</span>;</span><br><span class="line">      TProtocol outputProtocol = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">      TServerEventHandler eventHandler = <span class="keyword">null</span>;</span><br><span class="line">      ServerContext connectionContext = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        processor = processorFactory_.getProcessor(client_);</span><br><span class="line">        inputTransport = inputTransportFactory_.getTransport(client_);</span><br><span class="line">        outputTransport = outputTransportFactory_.getTransport(client_);</span><br><span class="line">        inputProtocol = inputProtocolFactory_.getProtocol(inputTransport);</span><br><span class="line">        outputProtocol = outputProtocolFactory_.getProtocol(outputTransport);	  </span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (<span class="keyword">true</span>) &#123;</span><br><span class="line">			<span class="comment">//process处理异常，则推送while循环，结束该线程</span></span><br><span class="line">            <span class="keyword">if</span>(stopped_ || !processor.process(inputProtocol, outputProtocol)) &#123;</span><br><span class="line">              <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (Exception x) &#123;</span><br><span class="line">        LOGGER.error(<span class="string">"Error occurred during processing of message."</span>, x);</span><br><span class="line">      &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="comment">//.........</span></span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　从上面代码中我们可以看到，它与TSimpleServer相同的是：它的serve方法内部也存在一个while循环，代码client = serverTransport_.accept();会一直阻塞，直到有客户端的连接（TServerTransport为TServerSocket，阻塞式IO实现）才返回。而不同之处则在于：新连接到达后，新生成的Socket会封装到WorkerProcess（实现了Runnable接口），放到线程池中运行！其特性就是多个客户单端并发执行，但是在每个客户端的内部，则是按顺序处理每个请求。</p>
<h4 id="AbstractNonblockingServer"><a href="#AbstractNonblockingServer" class="headerlink" title="AbstractNonblockingServer"></a>AbstractNonblockingServer</h4><p>　　在讲解TNonblockingServer、THsHaServer和TThreadedSelectorServer之前，我们先看看AbstractNonblockingServer。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractNonblockingServer</span> <span class="keyword">extends</span> <span class="title">TServer</span> </span>&#123;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractNonblockingServerArgs</span>&lt;<span class="title">T</span> <span class="keyword">extends</span> <span class="title">AbstractNonblockingServerArgs</span>&lt;<span class="title">T</span>&gt;&gt; <span class="keyword">extends</span> <span class="title">AbstractServerArgs</span>&lt;<span class="title">T</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">long</span> maxReadBufferBytes = Long.MAX_VALUE;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AbstractNonblockingServerArgs</span><span class="params">(TNonblockingServerTransport transport)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>(transport);</span><br><span class="line">      transportFactory(<span class="keyword">new</span> TFramedTransport.Factory());</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">AbstractNonblockingServer</span><span class="params">(AbstractNonblockingServerArgs args)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(args);</span><br><span class="line">    MAX_READ_BUFFER_BYTES = args.maxReadBufferBytes;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">serve</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (!startThreads()) &#123;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//其他非重要代码</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">boolean</span> <span class="title">startThreads</span><span class="params">()</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="keyword">boolean</span> <span class="title">requestInvoke</span><span class="params">(FrameBuffer frameBuffer)</span></span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractSelectThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">final</span> Selector selector;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">protected</span> <span class="keyword">final</span> Set&lt;FrameBuffer&gt; selectInterestChanges = <span class="keyword">new</span> HashSet&lt;FrameBuffer&gt;();</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AbstractSelectThread</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.selector = SelectorProvider.provider().openSelector();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">wakeupSelector</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      selector.wakeup();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">requestSelectInterestChange</span><span class="params">(FrameBuffer frameBuffer)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">synchronized</span> (selectInterestChanges) &#123;</span><br><span class="line">        selectInterestChanges.add(frameBuffer);</span><br><span class="line">      &#125;</span><br><span class="line">      selector.wakeup();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">processInterestChanges</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">synchronized</span> (selectInterestChanges) &#123;</span><br><span class="line">        <span class="keyword">for</span> (FrameBuffer fb : selectInterestChanges) &#123;</span><br><span class="line">          fb.changeSelectInterests();</span><br><span class="line">        &#125;</span><br><span class="line">        selectInterestChanges.clear();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">handleRead</span><span class="params">(SelectionKey key)</span> </span>&#123;</span><br><span class="line">      FrameBuffer buffer = (FrameBuffer) key.attachment();</span><br><span class="line">      <span class="keyword">if</span> (!buffer.read()) &#123;</span><br><span class="line">        cleanupSelectionKey(key);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      <span class="comment">// if the buffer's frame read is complete, invoke the method.</span></span><br><span class="line">      <span class="keyword">if</span> (buffer.isFrameFullyRead()) &#123;</span><br><span class="line">        <span class="keyword">if</span> (!requestInvoke(buffer)) &#123;</span><br><span class="line">          cleanupSelectionKey(key);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">handleWrite</span><span class="params">(SelectionKey key)</span> </span>&#123;</span><br><span class="line">      FrameBuffer buffer = (FrameBuffer) key.attachment();</span><br><span class="line">      <span class="keyword">if</span> (!buffer.write()) &#123;</span><br><span class="line">        cleanupSelectionKey(key);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　我们可以看到，在AbstractNonblockingServer中，最重要的一个抽象方法为：startThreads，以及一个内部抽象类：AbstractSelectThread。在AbstractSelectThread的构造方法中，我们初始化了一个Selector。下面我们看看TNonblockingServer对startThreads方法和AbstractSelectThread的run方法的实现</p>
<h2 id="TNonblockingServer"><a href="#TNonblockingServer" class="headerlink" title="TNonblockingServer"></a>TNonblockingServer</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TNonblockingServer</span> <span class="keyword">extends</span> <span class="title">AbstractNonblockingServer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> SelectAcceptThread selectAcceptThread_;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">startThreads</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">// start the selector</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      selectAcceptThread_ = <span class="keyword">new</span> SelectAcceptThread((TNonblockingServerTransport)serverTransport_);</span><br><span class="line">      selectAcceptThread_.start();</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">      LOGGER.error(<span class="string">"Failed to start selector thread!"</span>, e);</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">waitForShutdown</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    joinSelector();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">joinSelector</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      selectAcceptThread_.join();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;&#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">requestInvoke</span><span class="params">(FrameBuffer frameBuffer)</span> </span>&#123;</span><br><span class="line">    frameBuffer.invoke();</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> <span class="class"><span class="keyword">class</span> <span class="title">SelectAcceptThread</span> <span class="keyword">extends</span> <span class="title">AbstractSelectThread</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> TNonblockingServerTransport serverTransport;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SelectAcceptThread</span><span class="params">(<span class="keyword">final</span> TNonblockingServerTransport serverTransport)</span></span><br><span class="line">    <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.serverTransport = serverTransport;</span><br><span class="line">      serverTransport.registerSelector(selector);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">if</span> (eventHandler_ != <span class="keyword">null</span>) &#123;</span><br><span class="line">          eventHandler_.preServe();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">          select();</span><br><span class="line">          processInterestChanges();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (SelectionKey selectionKey : selector.keys()) &#123;</span><br><span class="line">          cleanupSelectionKey(selectionKey);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (Throwable t) &#123;</span><br><span class="line">        LOGGER.error(<span class="string">"run() exiting due to uncaught error"</span>, t);</span><br><span class="line">      &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">          selector.close();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">          LOGGER.error(<span class="string">"Got an IOException while closing selector!"</span>, e);</span><br><span class="line">        &#125;</span><br><span class="line">        stopped_ = <span class="keyword">true</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">select</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        selector.select();</span><br><span class="line"></span><br><span class="line">        Iterator&lt;SelectionKey&gt; selectedKeys = selector.selectedKeys().iterator();</span><br><span class="line">        <span class="keyword">while</span> (!stopped_ &amp;&amp; selectedKeys.hasNext()) &#123;</span><br><span class="line">          SelectionKey key = selectedKeys.next();</span><br><span class="line">          selectedKeys.remove();</span><br><span class="line">          <span class="keyword">if</span> (!key.isValid()) &#123;</span><br><span class="line">            <span class="keyword">continue</span>;</span><br><span class="line">          &#125;</span><br><span class="line"></span><br><span class="line">          <span class="keyword">if</span> (key.isAcceptable()) &#123;</span><br><span class="line">            handleAccept();</span><br><span class="line">          &#125; <span class="keyword">else</span> <span class="keyword">if</span> (key.isReadable()) &#123;</span><br><span class="line">            handleRead(key);</span><br><span class="line">          &#125; <span class="keyword">else</span> <span class="keyword">if</span> (key.isWritable()) &#123;</span><br><span class="line">            handleWrite(key);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">        LOGGER.warn(<span class="string">"Got an IOException while selecting!"</span>, e);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/**</span><br><span class="line">     * Accept a new connection.</span><br><span class="line">     */</span></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">handleAccept</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">      SelectionKey clientKey = <span class="keyword">null</span>;</span><br><span class="line">      TNonblockingTransport client = <span class="keyword">null</span>;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">// accept the connection</span></span><br><span class="line">        client = (TNonblockingTransport)serverTransport.accept();</span><br><span class="line">        clientKey = client.registerSelector(selector, SelectionKey.OP_READ);</span><br><span class="line"></span><br><span class="line">        <span class="comment">// add this key to the map</span></span><br><span class="line">          FrameBuffer frameBuffer = createFrameBuffer(client, clientKey, SelectAcceptThread.<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">          clientKey.attach(frameBuffer);</span><br><span class="line">      &#125; <span class="keyword">catch</span> (TTransportException tte) &#123;</span><br><span class="line">        <span class="comment">// something went wrong accepting.</span></span><br><span class="line">        LOGGER.warn(<span class="string">"Exception trying to accept!"</span>, tte);</span><br><span class="line">        tte.printStackTrace();</span><br><span class="line">        <span class="keyword">if</span> (clientKey != <span class="keyword">null</span>) cleanupSelectionKey(clientKey);</span><br><span class="line">        <span class="keyword">if</span> (client != <span class="keyword">null</span>) client.close();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="comment">// SelectAcceptThread</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　在startThreads方法中，生成了一个SelectAcceptThread对象，并调用了start方法，我们进入SelectAcceptThread的run方法，可以发现，其在一个线程中遍历SelectedKeys集合，根据interests，如acceptable、readable和writable则分别交由对应的方法处理，我们进入不同的方法及其调用的方法，可以发现都在同一个线程中运行（注意requestInvoke方法，下面会重点讲解）。这就印证了上面说的多个客户端的请求，实际上是通过一个线程（SelectAcceptThread）处理的，包括io读取和业务代码执行，很明显存在性能问题。</p>
<h2 id="THsHaServer"><a href="#THsHaServer" class="headerlink" title="THsHaServer"></a>THsHaServer</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">THsHaServer</span> <span class="keyword">extends</span> <span class="title">TNonblockingServer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Args</span> <span class="keyword">extends</span> <span class="title">AbstractNonblockingServerArgs</span>&lt;<span class="title">Args</span>&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> minWorkerThreads = <span class="number">5</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">int</span> maxWorkerThreads = Integer.MAX_VALUE;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">int</span> stopTimeoutVal = <span class="number">60</span>;</span><br><span class="line">    <span class="keyword">private</span> TimeUnit stopTimeoutUnit = TimeUnit.SECONDS;</span><br><span class="line">    <span class="keyword">private</span> ExecutorService executorService = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Args</span><span class="params">(TNonblockingServerTransport transport)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">super</span>(transport);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//各种参数设置方法</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">final</span> ExecutorService invoker;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">THsHaServer</span><span class="params">(Args args)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(args);</span><br><span class="line"></span><br><span class="line">    invoker = args.executorService == <span class="keyword">null</span> ? createInvokerPool(args) : args.executorService;</span><br><span class="line">    <span class="keyword">this</span>.args = args;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">void</span> <span class="title">waitForShutdown</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    joinSelector();</span><br><span class="line">    gracefullyShutdownInvokerPool();</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//创建一个线程池</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">static</span> ExecutorService <span class="title">createInvokerPool</span><span class="params">(Args options)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> minWorkerThreads = options.minWorkerThreads;</span><br><span class="line">    <span class="keyword">int</span> maxWorkerThreads = options.maxWorkerThreads;</span><br><span class="line">    <span class="keyword">int</span> stopTimeoutVal = options.stopTimeoutVal;</span><br><span class="line">    TimeUnit stopTimeoutUnit = options.stopTimeoutUnit;</span><br><span class="line"></span><br><span class="line">    LinkedBlockingQueue&lt;Runnable&gt; queue = <span class="keyword">new</span> LinkedBlockingQueue&lt;Runnable&gt;();</span><br><span class="line">    ExecutorService invoker = <span class="keyword">new</span> ThreadPoolExecutor(minWorkerThreads,</span><br><span class="line">      maxWorkerThreads, stopTimeoutVal, stopTimeoutUnit, queue);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">return</span> invoker;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">requestInvoke</span><span class="params">(FrameBuffer frameBuffer)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      Runnable invocation = getRunnable(frameBuffer);</span><br><span class="line">      invoker.execute(invocation);</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (RejectedExecutionException rx) &#123;</span><br><span class="line">      LOGGER.warn(<span class="string">"ExecutorService rejected execution!"</span>, rx);</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> Runnable <span class="title">getRunnable</span><span class="params">(FrameBuffer frameBuffer)</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Invocation(frameBuffer);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　我们可以看到THsHaServer继承自TNonblockingServer，既然如此，他也是在SelectAcceptThread线程中执行SelectionKey集合的遍历。但是其requestInvoke方法则与TNonblockingServer的不同。其将每次读取到的数据封装到一个Runnable中，交由线程池执行。所以THsHaServer是单个线程执行io读取，通过线程池执行业务代码。</p>
<h2 id="TThreadedSelectorServer"><a href="#TThreadedSelectorServer" class="headerlink" title="TThreadedSelectorServer"></a>TThreadedSelectorServer</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TThreadedSelectorServer</span> <span class="keyword">extends</span> <span class="title">AbstractNonblockingServer</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> AcceptThread acceptThread;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">final</span> Set&lt;SelectorThread&gt; selectorThreads = <span class="keyword">new</span> HashSet&lt;SelectorThread&gt;();</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">final</span> ExecutorService invoker;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">TThreadedSelectorServer</span><span class="params">(Args args)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">super</span>(args);</span><br><span class="line">    args.validate();</span><br><span class="line">    invoker = args.executorService == <span class="keyword">null</span> ? createDefaultExecutor(args) : args.executorService;</span><br><span class="line">    <span class="keyword">this</span>.args = args;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">startThreads</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">0</span>; i &lt; args.selectorThreads; ++i) &#123;</span><br><span class="line">        selectorThreads.add(<span class="keyword">new</span> SelectorThread(args.acceptQueueSizePerThread));</span><br><span class="line">      &#125;</span><br><span class="line">      acceptThread = <span class="keyword">new</span> AcceptThread((TNonblockingServerTransport) serverTransport_,</span><br><span class="line">        createSelectorThreadLoadBalancer(selectorThreads));</span><br><span class="line">      <span class="comment">//启动SelectorThread和acceptThread线程</span></span><br><span class="line">      <span class="keyword">for</span> (SelectorThread thread : selectorThreads) &#123;</span><br><span class="line">        thread.start();</span><br><span class="line">      &#125;</span><br><span class="line">      acceptThread.start();</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException e) &#123;&#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">boolean</span> <span class="title">requestInvoke</span><span class="params">(FrameBuffer frameBuffer)</span> </span>&#123;</span><br><span class="line">    Runnable invocation = getRunnable(frameBuffer);</span><br><span class="line">    <span class="keyword">if</span> (invoker != <span class="keyword">null</span>) &#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        invoker.execute(invocation);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (RejectedExecutionException rx) &#123;</span><br><span class="line">        LOGGER.warn(<span class="string">"ExecutorService rejected execution!"</span>, rx);</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="comment">// Invoke on the caller's thread</span></span><br><span class="line">      invocation.run();</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> Runnable <span class="title">getRunnable</span><span class="params">(FrameBuffer frameBuffer)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> Invocation(frameBuffer);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">static</span> ExecutorService <span class="title">createDefaultExecutor</span><span class="params">(Args options)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> (options.workerThreads &gt; <span class="number">0</span>) ? Executors.newFixedThreadPool(options.workerThreads) : <span class="keyword">null</span>;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> BlockingQueue&lt;TNonblockingTransport&gt; <span class="title">createDefaultAcceptQueue</span><span class="params">(<span class="keyword">int</span> queueSize)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> ArrayBlockingQueue&lt;TNonblockingTransport&gt;(queueSize);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> <span class="class"><span class="keyword">class</span> <span class="title">AcceptThread</span> <span class="keyword">extends</span> <span class="title">Thread</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> TNonblockingServerTransport serverTransport;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Selector acceptSelector;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> SelectorThreadLoadBalancer threadChooser;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">AcceptThread</span><span class="params">(TNonblockingServerTransport serverTransport,</span><br><span class="line">        SelectorThreadLoadBalancer threadChooser)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.serverTransport = serverTransport;</span><br><span class="line">      <span class="keyword">this</span>.threadChooser = threadChooser;</span><br><span class="line">      <span class="keyword">this</span>.acceptSelector = SelectorProvider.provider().openSelector();</span><br><span class="line">      <span class="keyword">this</span>.serverTransport.registerSelector(acceptSelector);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">        select();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">select</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        acceptSelector.select();</span><br><span class="line">        Iterator&lt;SelectionKey&gt; selectedKeys = acceptSelector.selectedKeys().iterator();</span><br><span class="line">        <span class="keyword">while</span> (!stopped_ &amp;&amp; selectedKeys.hasNext()) &#123;</span><br><span class="line">          SelectionKey key = selectedKeys.next();</span><br><span class="line">          selectedKeys.remove();</span><br><span class="line"></span><br><span class="line">          <span class="keyword">if</span> (key.isAcceptable()) &#123;</span><br><span class="line">            handleAccept();</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (IOException e) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">handleAccept</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">final</span> TNonblockingTransport client = doAccept();</span><br><span class="line">      <span class="keyword">if</span> (client != <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">final</span> SelectorThread targetThread = threadChooser.nextThread();</span><br><span class="line"></span><br><span class="line">        <span class="keyword">if</span> (args.acceptPolicy == Args.AcceptPolicy.FAST_ACCEPT || invoker == <span class="keyword">null</span>) &#123;</span><br><span class="line">          doAddAccept(targetThread, client);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">          <span class="keyword">try</span> &#123;</span><br><span class="line">            invoker.submit(<span class="keyword">new</span> Runnable() &#123;</span><br><span class="line">              <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">                doAddAccept(targetThread, client);</span><br><span class="line">              &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">          &#125; <span class="keyword">catch</span> (RejectedExecutionException rx) &#123;&#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> TNonblockingTransport <span class="title">doAccept</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">return</span> (TNonblockingTransport) serverTransport.accept();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">doAddAccept</span><span class="params">(SelectorThread thread, TNonblockingTransport client)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">if</span> (!thread.addAcceptedConnection(client)) &#123;</span><br><span class="line">        client.close();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="comment">// AcceptThread</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">protected</span> <span class="class"><span class="keyword">class</span> <span class="title">SelectorThread</span> <span class="keyword">extends</span> <span class="title">AbstractSelectThread</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> BlockingQueue&lt;TNonblockingTransport&gt; acceptedQueue;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">SelectorThread</span><span class="params">(<span class="keyword">int</span> maxPendingAccepts)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>(createDefaultAcceptQueue(maxPendingAccepts));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">addAcceptedConnection</span><span class="params">(TNonblockingTransport accepted)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        acceptedQueue.put(accepted);</span><br><span class="line">      &#125; <span class="keyword">catch</span> (InterruptedException e) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">      &#125;</span><br><span class="line">      selector.wakeup();</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">run</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">          <span class="comment">//内部循环调用SelectKeys</span></span><br><span class="line">          select();</span><br><span class="line">		  <span class="comment">//将新连接的SocketChannel注册到selector中，上面select()方法中的循环才有效果</span></span><br><span class="line">          processAcceptedConnections();</span><br><span class="line">          processInterestChanges();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">for</span> (SelectionKey selectionKey : selector.keys()) &#123;</span><br><span class="line">          cleanupSelectionKey(selectionKey);</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (Throwable t) &#123;</span><br><span class="line">        LOGGER.error(<span class="string">"run() on SelectorThread exiting due to uncaught error"</span>, t);</span><br><span class="line">      &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">          selector.close();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">          LOGGER.error(<span class="string">"Got an IOException while closing selector!"</span>, e);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// This will wake up the accept thread and the other selector threads</span></span><br><span class="line">        TThreadedSelectorServer.<span class="keyword">this</span>.stop();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">	</span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">select</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        <span class="comment">//此处本应该阻塞，但是每次新连接到来时，</span></span><br><span class="line">        <span class="comment">//都会调用addAcceptedConnection方法，它里面调用了wakeup方法，使其立即返回</span></span><br><span class="line">        selector.select();</span><br><span class="line"></span><br><span class="line">        Iterator&lt;SelectionKey&gt; selectedKeys = selector.selectedKeys().iterator();</span><br><span class="line">        <span class="keyword">while</span> (!stopped_ &amp;&amp; selectedKeys.hasNext()) &#123;</span><br><span class="line">          SelectionKey key = selectedKeys.next();</span><br><span class="line">          selectedKeys.remove();</span><br><span class="line"></span><br><span class="line">          <span class="keyword">if</span> (key.isReadable()) &#123;</span><br><span class="line">            handleRead(key);</span><br><span class="line">          &#125; <span class="keyword">else</span> <span class="keyword">if</span> (key.isWritable()) &#123;</span><br><span class="line">            handleWrite(key);</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;</span><br><span class="line">      &#125; <span class="keyword">catch</span> (IOException e) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">processAcceptedConnections</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">while</span> (!stopped_) &#123;</span><br><span class="line">        TNonblockingTransport accepted = acceptedQueue.poll();</span><br><span class="line">        <span class="keyword">if</span> (accepted == <span class="keyword">null</span>) &#123;</span><br><span class="line">          <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        registerAccepted(accepted);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">registerAccepted</span><span class="params">(TNonblockingTransport accepted)</span> </span>&#123;</span><br><span class="line">      SelectionKey clientKey = <span class="keyword">null</span>;</span><br><span class="line">      <span class="keyword">try</span> &#123;</span><br><span class="line">        clientKey = accepted.registerSelector(selector, SelectionKey.OP_READ);</span><br><span class="line"></span><br><span class="line">        FrameBuffer frameBuffer = createFrameBuffer(accepted, clientKey, SelectorThread.<span class="keyword">this</span>);</span><br><span class="line"></span><br><span class="line">        clientKey.attach(frameBuffer);</span><br><span class="line">      &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">        LOGGER.warn(<span class="string">"Failed to register accepted connection to selector!"</span>, e);</span><br><span class="line">        <span class="keyword">if</span> (clientKey != <span class="keyword">null</span>) &#123;</span><br><span class="line">          cleanupSelectionKey(clientKey);</span><br><span class="line">        &#125;</span><br><span class="line">        accepted.close();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125; <span class="comment">// SelectorThread</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> SelectorThreadLoadBalancer <span class="title">createSelectorThreadLoadBalancer</span><span class="params">(Collection&lt;? extends SelectorThread&gt; threads)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> SelectorThreadLoadBalancer(threads);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//round robin 负载均衡，好诡异的写法</span></span><br><span class="line">  <span class="keyword">protected</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">SelectorThreadLoadBalancer</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">final</span> Collection&lt;? extends SelectorThread&gt; threads;</span><br><span class="line">    <span class="keyword">private</span> Iterator&lt;? extends SelectorThread&gt; nextThreadIterator;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> &lt;T extends SelectorThread&gt; SelectorThreadLoadBalancer(Collection&lt;T&gt; threads) &#123;</span><br><span class="line">      <span class="keyword">if</span> (threads.isEmpty()) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="keyword">new</span> IllegalArgumentException(<span class="string">"At least one selector thread is required"</span>);</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">this</span>.threads = Collections.unmodifiableList(<span class="keyword">new</span> ArrayList&lt;T&gt;(threads));</span><br><span class="line">      nextThreadIterator = <span class="keyword">this</span>.threads.iterator();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> SelectorThread <span class="title">nextThread</span><span class="params">()</span> </span>&#123;</span><br><span class="line">      <span class="keyword">if</span> (!nextThreadIterator.hasNext()) &#123;</span><br><span class="line">        nextThreadIterator = threads.iterator();</span><br><span class="line">      &#125;</span><br><span class="line">      <span class="keyword">return</span> nextThreadIterator.next();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　在TThreadedSelectorServer中，定义了两个内部类AcceptThread和SelectorThread。其中AcceptThread用于监听客户端的连接，在其handleAccept方法中，获取到一个TNonblockingTransport（封装了SocketChannel）。<br>　　通过SelectorThreadLoadBalancer的round robin 负载均衡策略，选取一个SelectorThread，并将上面生成TNonblockingTransport放到SelectorThread的阻塞队列中，同时调用Selector的wakeup方法，使其run方法中的processAcceptedConnections能被执行到，最后调用了registerAccepted，将每个连接的SocketChannel都注册到Selector中。<br>　　最后，我们可以看到TThreadedSelectorServer通过两个SelectorThread线程的负载，实现io的读写，而业务代码则由createDefaultExecutor方法生成的线程池执行。</p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　根据上面几种不同的实现，我们简单做如下总结：<br>　　thread-per-connection：即每个客户端连接对于一个专属的工作线程，工作线程等待客户端发送数据、接收处理数据、返回响应数据然后继续等待新的数据的到来，这种实际可以参考thrift的TThreadPoolServer的实现。但是这种模型不适合高并发的情况。<br>　　thread-on-event：工作线程独立于客户端连接，只用来处理特定的事件，例如当有数据到来时（data received event），工作线程在应用级别处理这些数据。这种模型需要nio使用非阻塞的方式，同时需要事件监测机制。这种模型被称为消息驱动模型（Reactor Pattern），该模型我们可以参考xSocket。Dispatcher维护一个Selector，客户端连接注册到Selector，当有数据可读可写时，Dispatcher触发响应的事件。</p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://blog.csdn.net/whycold/article/details/8535932" target="_blank" rel="external">http://blog.csdn.net/whycold/article/details/8535932</a><br><a href="http://blog.csdn.net/azhao_dn/article/details/8898610" target="_blank" rel="external">http://blog.csdn.net/azhao_dn/article/details/8898610</a><br><a href="http://blog.csdn.net/azhao_dn/article/details/8899486" target="_blank" rel="external">http://blog.csdn.net/azhao_dn/article/details/8899486</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/8.RPC系列之Thrift TServer源码分析/" data-id="cijzzpv2u001x1cfsgly5i1wp" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/7.RPC系列之Thrift TProtocol源码分析" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/7.RPC系列之Thrift TProtocol源码分析/" class="article-date">
  <time datetime="2015-11-30T23:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/7.RPC系列之Thrift TProtocol源码分析/">RPC系列七之Thrift TProtocol源码分析</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　服务端与客户端通信，进行交换数据，这样就涉及到了消息的序列化和反序列化问题。thrift为我们提供了非常高效和强大的序列化接口，主要序列化接口如下：<br>　　1. TSimpleJSONProtocol：与其他框架，如fastjson、fasterxml等框架序列化的结果一致<br>　　2. TJSONProtocol：使用JSON的数据编码协议进行数据传输<br>　　3. TBinaryProtocol：自定义的二进制协议<br>　　4. TCompactProtocol：紧凑型二进制协议<br>　　5. TTupleProtocol：元组的序列化方式<br>　　6. TMultiplexedProtocol：用于一个服务支持多个service<br>　　下面我将逐一介绍各个协议的系列化结果，由简到难，最后重点介绍TTupleProtocol。首先我们看看最简单的TSimpleJSONProtocol协议。</p>
<h2 id="TSimpleJSONProtocol"><a href="#TSimpleJSONProtocol" class="headerlink" title="TSimpleJSONProtocol"></a>TSimpleJSONProtocol</h2><p>　　下面的单元测试代码将TSimpleJSONProtocol序列化的结果输出到一个文件中<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">serializeUser</span><span class="params">(TProtocol protocol)</span> <span class="keyword">throws</span> TException </span>&#123;</span><br><span class="line">    User user = <span class="keyword">new</span> User();</span><br><span class="line">    user.setType(<span class="number">1</span>);</span><br><span class="line">    user.setName(<span class="string">"张三"</span>);</span><br><span class="line">    user.write(protocol);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">simpleJsonTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        OutputStream os = <span class="keyword">new</span> FileOutputStream(<span class="string">"serialize\\simplejson.data"</span>);</span><br><span class="line">        serializeUser(<span class="keyword">new</span> TSimpleJSONProtocol(<span class="keyword">new</span> TIOStreamTransport(os)));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　文件中的内容为：<strong>{“type”:1,”name”:”张三”}</strong>，可以看到，它与常用的fastjson等框架序列化结果一致。下面我们再看看TJSONProtocol的序列化结果</p>
<h2 id="TJSONProtocol"><a href="#TJSONProtocol" class="headerlink" title="TJSONProtocol"></a>TJSONProtocol</h2><p>　　TJSONProtocol的构造方法中，第二个参数用于指定序列化时是否将字段名序列化，两者的序列化结果可以通过如下测试代码区别：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">jsonTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        OutputStream os = <span class="keyword">new</span> FileOutputStream(<span class="string">"serialize\\json.data"</span>);</span><br><span class="line">        serializeUser(<span class="keyword">new</span> TJSONProtocol(<span class="keyword">new</span> TIOStreamTransport(os)));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">jsonNameTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        OutputStream os = <span class="keyword">new</span> FileOutputStream(<span class="string">"serialize\\jsonName.data"</span>);</span><br><span class="line">        serializeUser(<span class="keyword">new</span> TJSONProtocol(<span class="keyword">new</span> TIOStreamTransport(os), <span class="keyword">true</span>));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　测试方法jsonTest和jsonNameTest的输出结果分别为：<br>{“1”:{“i32”:1},”2”:{“str”:”张三”}}<br>{“type”:{“i32”:1},”name”:{“str”:”张三”}}<br>　　两者的不同之处在属性字段的表示方法，一个是属性字段对应的id号，另一个则是属性字段的名称。</p>
<h2 id="TTupleProtocol"><a href="#TTupleProtocol" class="headerlink" title="TTupleProtocol"></a>TTupleProtocol</h2><p>　　我们先普及一下tuple的概念，用java的朋友可能对这个概念比较陌生，但是在python等脚本语言中就已经内置了对它的支持。<br>　　其实元组和列表list一样，都可能用于数据存储，包含多个数据；但是和列表不同的是：列表只能存储相同的数据类型，而元组不一样，它可以存储不同的数据类型，比如同时存储int、string、list等，并且可以根据需求无限扩展。<br>　　首先我们调整一下User的模型，修改后如下：<br><figure class="highlight thrift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">User</span> </span>&#123;</span><br><span class="line">    <span class="number">1</span>: <span class="keyword">required</span> <span class="built_in">i32</span> type</span><br><span class="line">    <span class="number">2</span>: <span class="keyword">optional</span> <span class="built_in">string</span> name</span><br><span class="line">    <span class="number">3</span>: <span class="keyword">optional</span> <span class="built_in">string</span> sex</span><br><span class="line">    <span class="number">4</span>: <span class="keyword">optional</span> <span class="built_in">string</span> school</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　我们运行下面两个测试方法，看看输出的结果：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="annotation">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">tupleTest</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        OutputStream os = <span class="keyword">new</span> FileOutputStream(<span class="string">"serialize\\tuple.data"</span>);</span><br><span class="line">        TTupleProtocol protocol = <span class="keyword">new</span> TTupleProtocol(<span class="keyword">new</span> TIOStreamTransport(os));</span><br><span class="line">        User user = <span class="keyword">new</span> User();</span><br><span class="line">        user.setType(<span class="number">1</span>);</span><br><span class="line">        user.setName(<span class="string">"张三"</span>);</span><br><span class="line">        user.write(protocol);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="annotation">@Test</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">tupleTest2</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        OutputStream os = <span class="keyword">new</span> FileOutputStream(<span class="string">"serialize\\tuple2.data"</span>);</span><br><span class="line">        TTupleProtocol protocol = <span class="keyword">new</span> TTupleProtocol(<span class="keyword">new</span> TIOStreamTransport(os));</span><br><span class="line">        User user = <span class="keyword">new</span> User();</span><br><span class="line">        user.setType(<span class="number">1</span>);</span><br><span class="line">        user.setName(<span class="string">"张三"</span>);</span><br><span class="line">        user.setSchool(<span class="string">"实验小学"</span>);</span><br><span class="line">        user.write(protocol);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">        e.printStackTrace();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　两个测试方法唯一的区别在于第二个方法多了一行代码：user.setSchool(“实验小学”);，下图为输出结果。可以看到，TTupleProtocol的序列话方式是按照User中属性的id顺序，逐个输出属性值，下图中的“乱码”产生原因，后面我们会进入源码再解释！<br><img src="/images/thrift-protocol-tuple.jpg" alt="thrift-protocol-tuple.jpg"><br>　　调用User的write方法后，程序最终会执行到其内部类UserTupleScheme的write方法，核心代码如下。注意代码中的注释是根据tupleTest方法的执行注释的。<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">UserTupleScheme</span> <span class="keyword">extends</span> <span class="title">TupleScheme</span>&lt;<span class="title">User</span>&gt; </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(org.apache.thrift.protocol.TProtocol prot, User struct)</span> <span class="keyword">throws</span> org.apache.thrift.TException </span>&#123;</span><br><span class="line">    TTupleProtocol oprot = (TTupleProtocol) prot;</span><br><span class="line">    <span class="comment">//struct.type取值为1</span></span><br><span class="line">    <span class="comment">//int应暂用4个字节，实际只占用1个字节</span></span><br><span class="line">    oprot.writeI32(struct.type);</span><br><span class="line">    BitSet optionals = <span class="keyword">new</span> BitSet();</span><br><span class="line">    <span class="keyword">if</span> (struct.isSetName()) &#123;</span><br><span class="line">      optionals.set(<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (struct.isSetSex()) &#123;</span><br><span class="line">      optionals.set(<span class="number">1</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (struct.isSetSchool()) &#123;</span><br><span class="line">      optionals.set(<span class="number">2</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//占用1个字节</span></span><br><span class="line">    oprot.writeBitSet(optionals, <span class="number">3</span>);</span><br><span class="line">    <span class="keyword">if</span> (struct.isSetName()) &#123;</span><br><span class="line">      <span class="comment">//占用7个字节，第一个字节为name值的长度，后六个为name的值</span></span><br><span class="line">      <span class="comment">//一个汉字在utf-8中占用3个字节，这里有两个汉字</span></span><br><span class="line">      oprot.writeString(struct.name);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (struct.isSetSex()) &#123;</span><br><span class="line">      oprot.writeString(struct.sex);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (struct.isSetSchool()) &#123;</span><br><span class="line">      oprot.writeString(struct.school);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="annotation">@Override</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">(org.apache.thrift.protocol.TProtocol prot, User struct)</span> <span class="keyword">throws</span> org.apache.thrift.TException </span>&#123;</span><br><span class="line">    TTupleProtocol iprot = (TTupleProtocol) prot;</span><br><span class="line">    struct.type = iprot.readI32();</span><br><span class="line">    struct.setTypeIsSet(<span class="keyword">true</span>);</span><br><span class="line">    BitSet incoming = iprot.readBitSet(<span class="number">3</span>);</span><br><span class="line">    <span class="keyword">if</span> (incoming.get(<span class="number">0</span>)) &#123;</span><br><span class="line">      struct.name = iprot.readString();</span><br><span class="line">      struct.setNameIsSet(<span class="keyword">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (incoming.get(<span class="number">1</span>)) &#123;</span><br><span class="line">      struct.sex = iprot.readString();</span><br><span class="line">      struct.setSexIsSet(<span class="keyword">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span> (incoming.get(<span class="number">2</span>)) &#123;</span><br><span class="line">      struct.school = iprot.readString();</span><br><span class="line">      struct.setSchoolIsSet(<span class="keyword">true</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　我们直接进入文件系统，可以看到tuple.data文件占用9个字节，而上面的注释中字节总数和恰好为9个，基本可以说明注释正确。上面的代码中写入了BitSet的值，貌似没有用处。<br>　　实际上它在UserTupleScheme的read方法中用到了，其主要作用为：<strong>反序列化时确定某个optional类型的属性是否有值</strong>。最后我们通过下面一个表格描述一下tupleTest方法生成的文件的内容的格式，其中第二行为文件的内容。注意type属性为required类型，必然存在值，其状态无需保存在bitset中，序列化是最先处理。</p>
<table>
<thead>
<tr>
<th>type值</th>
<th>bitset值</th>
<th>name值长度</th>
<th>name值</th>
</tr>
</thead>
<tbody>
<tr>
<td>2(varint表示)</td>
<td>1(字节)</td>
<td>6</td>
<td>张三</td>
</tr>
<tr>
<td>1个字节</td>
<td>1个字节</td>
<td>1个字节</td>
<td>6个字节</td>
</tr>
</tbody>
</table>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　到这里本章就暂时结束了，至于TBinaryProtocol和TCompactProtocol等协议，请大家自行分析，这里便不再做介绍了。最后我们对各个协议的序列化大小做个基本的排序。后面三个的大小顺序还需要看实际的数据情况，但是基本上可以确定TTupleProtocol最小，TCompactProtocol其次。<br>　　TTupleProtocol &lt; TCompactProtocol &lt; TSimpleJSONProtocol &lt; TBinaryProtocol &lt; TJSONProtocol</p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://blog.csdn.net/whycold/article/details/8535932" target="_blank" rel="external">http://blog.csdn.net/whycold/article/details/8535932</a><br><a href="http://blog.csdn.net/azhao_dn/article/details/8898610" target="_blank" rel="external">http://blog.csdn.net/azhao_dn/article/details/8898610</a><br><a href="http://blog.csdn.net/azhao_dn/article/details/8899486" target="_blank" rel="external">http://blog.csdn.net/azhao_dn/article/details/8899486</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/7.RPC系列之Thrift TProtocol源码分析/" data-id="cijzzpv2y00211cfsi3a18eag" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/6.RPC系列之Thrift Transport源码分析" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/6.RPC系列之Thrift Transport源码分析/" class="article-date">
  <time datetime="2015-11-30T22:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/6.RPC系列之Thrift Transport源码分析/">RPC系列六之Thrift Transport源码分析</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　作为一个rpc框架，最基础的功能便是要提供数据传输的功能，所以我们最开始介绍传输层。thrift的传输层实现包括TServerTransport和TTransport，他们都实现了一个接口java.io.Closeable。</p>
<h2 id="TServerTransport"><a href="#TServerTransport" class="headerlink" title="TServerTransport"></a>TServerTransport</h2><p>　　抽象类TServerTransport有以下两个实现：<br>　　1. TServerSocket：服务端阻塞IO实现，封装了java.net.ServerSocket。直接继承自TServerTransport。<br>　　2. TNonblockingServerSocket：服务端NIO实现，封装了java.nio.channels.ServerSocketChannel和java.nio.channels.Selector等。其继承自TNonblockingServerTransport，而其又继承自TServerTransport。</p>
<h4 id="TServerTransport-1"><a href="#TServerTransport-1" class="headerlink" title="TServerTransport"></a>TServerTransport</h4><p>　　接下来，我们贴出上面几个类的核心代码，首先是TServerTransport：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">TServerTransport</span> <span class="keyword">implements</span> <span class="title">Closeable</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">AbstractServerTransportArgs</span>&lt;<span class="title">T</span> <span class="keyword">extends</span> <span class="title">AbstractServerTransportArgs</span>&lt;<span class="title">T</span>&gt;&gt; </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> backlog = <span class="number">0</span>; <span class="comment">// A value of 0 means the default value will be used (currently set at 50)</span></span><br><span class="line">    <span class="keyword">int</span> clientTimeout = <span class="number">0</span>;</span><br><span class="line">    InetSocketAddress bindAddr;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> T <span class="title">port</span><span class="params">(<span class="keyword">int</span> port)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.bindAddr = <span class="keyword">new</span> InetSocketAddress(port);</span><br><span class="line">      <span class="keyword">return</span> (T) <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//省略其他初始化方法</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> TTransport <span class="title">accept</span><span class="params">()</span> <span class="keyword">throws</span> TTransportException </span>&#123;</span><br><span class="line">    TTransport transport = acceptImpl();</span><br><span class="line">    <span class="keyword">if</span> (transport == <span class="keyword">null</span>) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> TTransportException(<span class="string">"accept() may not return NULL"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> transport;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> <span class="keyword">abstract</span> TTransport <span class="title">acceptImpl</span><span class="params">()</span> <span class="keyword">throws</span> TTransportException</span>;</span><br><span class="line">  <span class="comment">//省略其他初始化方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看到，其内部类AbstractServerTransportArgs封装了服务端的参数，如端口，超时等，主要用于初始化参数设置，该思想与构造者（Builder）模式类似。其还有一个非常重要的抽象方法：<strong>acceptImpl</strong>。接下来，我们进入子类TServerSocket看看其对这个方法的实现</p>
<h4 id="TServerSocket"><a href="#TServerSocket" class="headerlink" title="TServerSocket"></a>TServerSocket</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TServerSocket</span> <span class="keyword">extends</span> <span class="title">TServerTransport</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> ServerSocket serverSocket_ = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">int</span> clientTimeout_ = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">ServerSocketTransportArgs</span> </span><br><span class="line">                            <span class="keyword">extends</span> <span class="title">AbstractServerTransportArgs</span>&lt;<span class="title">ServerSocketTransportArgs</span>&gt; </span>&#123;</span><br><span class="line">    ServerSocket serverSocket;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ServerSocketTransportArgs <span class="title">serverSocket</span><span class="params">(ServerSocket serverSocket)</span> </span>&#123;</span><br><span class="line">      <span class="keyword">this</span>.serverSocket = serverSocket;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//其他的构造方法省略</span></span><br><span class="line">  </span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">TServerSocket</span><span class="params">(ServerSocketTransportArgs args)</span> <span class="keyword">throws</span> TTransportException </span>&#123;</span><br><span class="line">    clientTimeout_ = args.clientTimeout;</span><br><span class="line">    <span class="keyword">if</span> (args.serverSocket != <span class="keyword">null</span>) &#123;</span><br><span class="line">      <span class="keyword">this</span>.serverSocket_ = args.serverSocket;</span><br><span class="line">      <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="comment">// Make server socket</span></span><br><span class="line">      serverSocket_ = <span class="keyword">new</span> ServerSocket();</span><br><span class="line">      <span class="comment">// Prevent 2MSL delay problem on server restarts</span></span><br><span class="line">      serverSocket_.setReuseAddress(<span class="keyword">true</span>);</span><br><span class="line">      <span class="comment">// Bind to listening port</span></span><br><span class="line">      serverSocket_.bind(args.bindAddr, args.backlog);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException ioe) &#123;</span><br><span class="line">      close();</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> TSocket <span class="title">acceptImpl</span><span class="params">()</span> <span class="keyword">throws</span> TTransportException </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      Socket result = serverSocket_.accept();</span><br><span class="line">      TSocket result2 = <span class="keyword">new</span> TSocket(result);</span><br><span class="line">      result2.setTimeout(clientTimeout_);</span><br><span class="line">      <span class="keyword">return</span> result2;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException iox) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> TTransportException(iox);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  .......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　在上面的类中，我们实现了AbstractServerTransportArgs抽象类和方法acceptImpl。在acceptImpl方法中，每次客户端连接后，我们都要将新的Socket封装到TSocket中并返回，TSocket类请查看后文，这里不做介绍。下面我们看看子类TNonblockingServerSocket对acceptImpl方法的实现</p>
<h4 id="TNonblockingServerSocket"><a href="#TNonblockingServerSocket" class="headerlink" title="TNonblockingServerSocket"></a>TNonblockingServerSocket</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">TNonblockingServerTransport</span> <span class="keyword">extends</span> <span class="title">TServerTransport</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title">registerSelector</span><span class="params">(Selector selector)</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TNonblockingServerSocket</span> <span class="keyword">extends</span> <span class="title">TNonblockingServerTransport</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> ServerSocketChannel serverSocketChannel = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> ServerSocket serverSocket_ = <span class="keyword">null</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">int</span> clientTimeout_ = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">NonblockingAbstractServerSocketArgs</span> <span class="keyword">extends</span></span><br><span class="line">      <span class="title">AbstractServerTransportArgs</span>&lt;<span class="title">NonblockingAbstractServerSocketArgs</span>&gt; </span>&#123;&#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">//其他构造方法省略</span></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">TNonblockingServerSocket</span><span class="params">(NonblockingAbstractServerSocketArgs args)</span> <span class="keyword">throws</span> TTransportException </span>&#123;</span><br><span class="line">    clientTimeout_ = args.clientTimeout;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      serverSocketChannel = ServerSocketChannel.open();</span><br><span class="line">      serverSocketChannel.configureBlocking(<span class="keyword">false</span>);</span><br><span class="line"></span><br><span class="line">      <span class="comment">// Make server socket</span></span><br><span class="line">      serverSocket_ = serverSocketChannel.socket();</span><br><span class="line">      <span class="comment">// Prevent 2MSL delay problem on server restarts</span></span><br><span class="line">      serverSocket_.setReuseAddress(<span class="keyword">true</span>);</span><br><span class="line">      <span class="comment">// Bind to listening port</span></span><br><span class="line">      serverSocket_.bind(args.bindAddr, args.backlog);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException ioe) &#123;</span><br><span class="line">      serverSocket_ = <span class="keyword">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">protected</span> TNonblockingSocket <span class="title">acceptImpl</span><span class="params">()</span> <span class="keyword">throws</span> TTransportException </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      SocketChannel socketChannel = serverSocketChannel.accept();</span><br><span class="line">      <span class="keyword">if</span> (socketChannel == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">null</span>;</span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      TNonblockingSocket tsocket = <span class="keyword">new</span> TNonblockingSocket(socketChannel);</span><br><span class="line">      tsocket.setTimeout(clientTimeout_);</span><br><span class="line">      <span class="keyword">return</span> tsocket;</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException iox) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> TTransportException(iox);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">registerSelector</span><span class="params">(Selector selector)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="comment">// Register the server socket channel, indicating an interest in</span></span><br><span class="line">      <span class="comment">// accepting new connections</span></span><br><span class="line">      serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (ClosedChannelException e) &#123;</span><br><span class="line">      <span class="comment">// this shouldn't happen, ideally...</span></span><br><span class="line">      <span class="comment">// <span class="doctag">TODO:</span> decide what to do with this.</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">//省略其他的方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　我们可以看到，在TNonblockingServerSocket的acceptImpl 方法中，每次客户端的连接，最后都会得到一个java.nio.channels.SocketChannel，并将其封装到TNonblockingSocket中再返回。TNonblockingSocket功能请看下面一节的介绍。</p>
<h2 id="TTransport"><a href="#TTransport" class="headerlink" title="TTransport"></a>TTransport</h2><p>　　在thrift中，抽象类TTransport作为所有数据传输类的基类，其实现主要包括以下几种：<br>　　1. <strong>TSocket</strong>：客户端IO实现，封装了java.net.Socket。继承自TIOStreamTransport，而其又继承自TTransport。<br>　　2. <strong>TNonblockingSocket</strong>：客户端NIO实现，封装了SocketChannel。继承自TNonblockingTransport，而其又继承自TTransport。<br>　　3. <strong>TFramedTransport</strong>：TTransport的一个包裹类，内部维护了一个TTransport对象 <strong>transport_</strong> 。调用TFramedTransport的write方法时，都会先写入TByteArrayOutputStream(ByteArrayOutputStream的一个简单子类)中。调用其flush方法时，先计算出TByteArrayOutputStream中数据的长度，再向transport_写入数据长度，最后写入实际的数据。其实就是一个粘包掉包的处理<br>　　4. <strong>TZlibTransport</strong>：数据压缩传输，其只是在net的输入输出流上包裹了java.util.zip.InflaterInputStream和java.util.zip.DeflaterOutputStream，实现数据的压缩与解压。<br>　　5. <strong>TSaslTransport</strong>：有TSaslClientTransport和TSaslServerTransport的实现。SASL 对用户使用两个重要的标识符。验证 ID (authid) 是用于验证用户的用户 ID。验证 ID 授予用户系统访问权限，授权 ID (userid) 用于检查是否允许用户使用特定选项，这点上与OAuth2.0类似。其主要是对java提供的sasl的封装，几乎用不上，这里我们不做过多的介绍。<br>　　6. <strong>TFileTransport</strong>：文件传输类，允许client将文件传给server，允许server将收到的数据写到文件中。<br>　　7. <strong>THttpClient</strong>：采用http进行rpc调用，其依赖于开源的http组件：httpclient。注意，其服务端的实现为org.apache.thrift.server.TServlet，继承自javax.servlet.http.HttpServlet。<br>　　下面我们选取两个最常用的客户端实现TSocket和TNonblockingSocket进行分析。</p>
<h4 id="TSocket"><a href="#TSocket" class="headerlink" title="TSocket"></a>TSocket</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.net.Socket;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TSocket</span> <span class="keyword">extends</span> <span class="title">TIOStreamTransport</span> </span>&#123;</span><br><span class="line">  <span class="keyword">private</span> Socket socket_ = <span class="keyword">null</span>;</span><br><span class="line">  <span class="keyword">private</span> String host_  = <span class="keyword">null</span>;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">int</span> port_ = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">int</span> socketTimeout_ = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">int</span> connectTimeout_ = <span class="number">0</span>;</span><br><span class="line">  </span><br><span class="line">  ......</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="title">TSocket</span><span class="params">(String host, <span class="keyword">int</span> port, <span class="keyword">int</span> socketTimeout, <span class="keyword">int</span> connectTimeout)</span> </span>&#123;</span><br><span class="line">    host_ = host;</span><br><span class="line">    port_ = port;</span><br><span class="line">    socketTimeout_ = socketTimeout;</span><br><span class="line">    connectTimeout_ = connectTimeout;</span><br><span class="line">    initSocket();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="keyword">void</span> <span class="title">initSocket</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    socket_ = <span class="keyword">new</span> Socket();</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      socket_.setSoLinger(<span class="keyword">false</span>, <span class="number">0</span>);</span><br><span class="line">      socket_.setTcpNoDelay(<span class="keyword">true</span>);</span><br><span class="line">      socket_.setKeepAlive(<span class="keyword">true</span>);</span><br><span class="line">      socket_.setSoTimeout(socketTimeout_);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (SocketException sx) &#123;</span><br><span class="line">      LOGGER.error(<span class="string">"Could not configure socket."</span>, sx);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isOpen</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (socket_ == <span class="keyword">null</span>) &#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> socket_.isConnected();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">open</span><span class="params">()</span> <span class="keyword">throws</span> TTransportException </span>&#123;</span><br><span class="line">    ......</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      socket_.connect(<span class="keyword">new</span> InetSocketAddress(host_, port_), connectTimeout_);</span><br><span class="line">      inputStream_ = <span class="keyword">new</span> BufferedInputStream(socket_.getInputStream(), <span class="number">1024</span>);</span><br><span class="line">      outputStream_ = <span class="keyword">new</span> BufferedOutputStream(socket_.getOutputStream(), <span class="number">1024</span>);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException iox) &#123;</span><br><span class="line">      close();</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> TTransportException(TTransportException.NOT_OPEN, iox);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  ......</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>　　可以看出，他仅仅是封装了java.net.Socket的初始化和连接的过程，算得上是通用的代码。而其父类TIOStreamTransport只仅仅是进行了基本的io操作read和write，这里不再细究。注意，这里我们采用的是阻塞式的socket。</p>
<h4 id="TNonblockingSocket"><a href="#TNonblockingSocket" class="headerlink" title="TNonblockingSocket"></a>TNonblockingSocket</h4><p>　　这里，我们重点关注TNonblockingSocket和其父类TNonblockingTransport的实现，下面仍然只列出最关键的代码<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="class"><span class="keyword">class</span> <span class="title">TNonblockingTransport</span> <span class="keyword">extends</span> <span class="title">TTransport</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">boolean</span> <span class="title">startConnect</span><span class="params">()</span> <span class="keyword">throws</span> IOException</span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">boolean</span> <span class="title">finishConnect</span><span class="params">()</span> <span class="keyword">throws</span> IOException</span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> SelectionKey <span class="title">registerSelector</span><span class="params">(Selector selector, <span class="keyword">int</span> interests)</span> <span class="keyword">throws</span> IOException</span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">(ByteBuffer buffer)</span> <span class="keyword">throws</span> IOException</span>;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">int</span> <span class="title">write</span><span class="params">(ByteBuffer buffer)</span> <span class="keyword">throws</span> IOException</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TNonblockingSocket</span> <span class="keyword">extends</span> <span class="title">TNonblockingTransport</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">final</span> SocketAddress socketAddress_;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">private</span> <span class="keyword">final</span> SocketChannel socketChannel_;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">private</span> <span class="title">TNonblockingSocket</span><span class="params">(SocketChannel socketChannel, <span class="keyword">int</span> timeout, SocketAddress socketAddress)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    socketChannel_ = socketChannel;</span><br><span class="line">    socketAddress_ = socketAddress;</span><br><span class="line"></span><br><span class="line">    socketChannel.configureBlocking(<span class="keyword">false</span>);</span><br><span class="line"></span><br><span class="line">    Socket socket = socketChannel.socket();</span><br><span class="line">    socket.setSoLinger(<span class="keyword">false</span>, <span class="number">0</span>);</span><br><span class="line">    socket.setTcpNoDelay(<span class="keyword">true</span>);</span><br><span class="line">    socket.setKeepAlive(<span class="keyword">true</span>);</span><br><span class="line">    setTimeout(timeout);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> SelectionKey <span class="title">registerSelector</span><span class="params">(Selector selector, <span class="keyword">int</span> interests)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> socketChannel_.register(selector, interests);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setTimeout</span><span class="params">(<span class="keyword">int</span> timeout)</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      socketChannel_.socket().setSoTimeout(timeout);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (SocketException sx) &#123;</span><br><span class="line">      LOGGER.warn(<span class="string">"Could not set socket timeout."</span>, sx);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">isOpen</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="comment">// isConnected() does not return false after close(), but isOpen() does</span></span><br><span class="line">    <span class="keyword">return</span> socketChannel_.isOpen() &amp;&amp; socketChannel_.isConnected();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">open</span><span class="params">()</span> <span class="keyword">throws</span> TTransportException </span>&#123;</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">"open() is not implemented for TNonblockingSocket"</span>);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">(ByteBuffer buffer)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> socketChannel_.read(buffer);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">read</span><span class="params">(<span class="keyword">byte</span>[] buf, <span class="keyword">int</span> off, <span class="keyword">int</span> len)</span> <span class="keyword">throws</span> TTransportException </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> ((socketChannel_.validOps() &amp; SelectionKey.OP_READ) != SelectionKey.OP_READ) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> TTransportException(TTransportException.NOT_OPEN,</span><br><span class="line">        <span class="string">"Cannot read from write-only socket channel"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> socketChannel_.read(ByteBuffer.wrap(buf, off, len));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException iox) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> TTransportException(TTransportException.UNKNOWN, iox);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">int</span> <span class="title">write</span><span class="params">(ByteBuffer buffer)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> socketChannel_.write(buffer);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">write</span><span class="params">(<span class="keyword">byte</span>[] buf, <span class="keyword">int</span> off, <span class="keyword">int</span> len)</span> <span class="keyword">throws</span> TTransportException </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> ((socketChannel_.validOps() &amp; SelectionKey.OP_WRITE) != SelectionKey.OP_WRITE) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> TTransportException(TTransportException.NOT_OPEN,</span><br><span class="line">        <span class="string">"Cannot write to write-only socket channel"</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      socketChannel_.write(ByteBuffer.wrap(buf, off, len));</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException iox) &#123;</span><br><span class="line">      <span class="keyword">throw</span> <span class="keyword">new</span> TTransportException(TTransportException.UNKNOWN, iox);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">flush</span><span class="params">()</span> <span class="keyword">throws</span> TTransportException </span>&#123;</span><br><span class="line">    <span class="comment">// Not supported by SocketChannel.</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">close</span><span class="params">()</span> </span>&#123;</span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">      socketChannel_.close();</span><br><span class="line">    &#125; <span class="keyword">catch</span> (IOException iox) &#123;</span><br><span class="line">      LOGGER.warn(<span class="string">"Could not close socket."</span>, iox);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">startConnect</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> socketChannel_.connect(socketAddress_);</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">public</span> <span class="keyword">boolean</span> <span class="title">finishConnect</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> socketChannel_.finishConnect();</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　可以看到，这里仍然只是对java nio的一个简单封装，请大家自行查找资料。</p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　到这里，我们基本上就分析完Transport了。简单点说，其就是对Java的ServerSocket、Socket、ServerSocketChannel和SocketChannel的一层简单封装，为我们提供最底层的数据传输。那么问题来了，我们传输的数据格式是什么样的呢！只有定义好了数据的传输格式，客户端和服务端才能通解析Transport传递过来的数据。下一篇我们将介绍thrift的数据交换协议TProtocol</p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://blog.csdn.net/whycold/article/details/8535932" target="_blank" rel="external">http://blog.csdn.net/whycold/article/details/8535932</a><br><a href="http://blog.csdn.net/azhao_dn/article/details/8898610" target="_blank" rel="external">http://blog.csdn.net/azhao_dn/article/details/8898610</a><br><a href="http://blog.csdn.net/azhao_dn/article/details/8899486" target="_blank" rel="external">http://blog.csdn.net/azhao_dn/article/details/8899486</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/6.RPC系列之Thrift Transport源码分析/" data-id="cijzzpv3100251cfskw5v1z4n" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-rpc/5.RPC系列之Thrift入门" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/rpc/5.RPC系列之Thrift入门/" class="article-date">
  <time datetime="2015-11-30T21:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/rpc/">rpc</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/rpc/5.RPC系列之Thrift入门/">RPC系列五之Thrift入门</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u7B80_u4ECB"><a href="#u7B80_u4ECB" class="headerlink" title="简介"></a>简介</h2><p>　　Thrift是一个软件框架，用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎，以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 等编程语言间无缝结合的、高效的服务。Thrift最初由facebook开发，07年四月开放源码，08年5月进入apache孵化器。它允许你在一个简单的文件中定义数据类型和服务接口。以该文件作为输入文件，编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。</p>
<h2 id="thrift_u6587_u4EF6"><a href="#thrift_u6587_u4EF6" class="headerlink" title="thrift文件"></a>thrift文件</h2><p>　　thrift文件支持的数据类型包括基本类型、结构体类型、异常类型和服务类型。同时它允许thrift文件包含，用户需要使用thrift文件名作为前缀访问被包含的对象，详见后面的实例<br>　　基本类型：<br>　　　　bool：布尔值，true 或 false，对应 Java 的 boolean<br>　　　　byte：8 位有符号整数，对应 Java 的 byte<br>　　　　i16：16 位有符号整数，对应 Java 的 short<br>　　　　i32：32 位有符号整数，对应 Java 的 int<br>　　　　i64：64 位有符号整数，对应 Java 的 long<br>　　　　double：64 位浮点数，对应 Java 的 double<br>　　　　string：utf-8编码的字符串，对应 Java 的 String<br>　　结构体类型：<br>　　　　struct：定义公共的对象，类似于 C 语言中的结构体定义，在 Java 中是一个 JavaBean<br>　　容器类型：<br>　　　　list：对应 Java 的 ArrayList<br>　　　　set：对应 Java 的 HashSet<br>　　　　map：对应 Java 的 HashMap<br>　　异常类型：<br>　　　　exception：对应 Java 的 Exception<br>　　服务类型：<br>　　　　service：对应服务的类，Service支持继承，一个service可使用extends关键字继承另一个service<br>　　在thrift中，每个类型又都对应一个数字，映射关系保存在类中。序列化时，直接序列化类型对应的数字，后面再详细介绍<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> org.apache.thrift.protocol</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">TType</span> </span>&#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> STOP   = <span class="number">0</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> VOID   = <span class="number">1</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> BOOL   = <span class="number">2</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> BYTE   = <span class="number">3</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> DOUBLE = <span class="number">4</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> I16    = <span class="number">6</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> I32    = <span class="number">8</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> I64    = <span class="number">10</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> STRING = <span class="number">11</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> STRUCT = <span class="number">12</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> MAP    = <span class="number">13</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> SET    = <span class="number">14</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> LIST   = <span class="number">15</span>;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">byte</span> ENUM   = <span class="number">16</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="u793A_u4F8B"><a href="#u793A_u4F8B" class="headerlink" title="示例"></a>示例</h2><p>　　下面将采用maven + thrift模式进行开发。thrift定义文件转java代码则是通过maven插件org.apache.thrift.tools:thrift-maven-plugin插件完成的，插件地址为：<a href="https://github.com/dtrott/maven-thrift-plugin。" target="_blank" rel="external">https://github.com/dtrott/maven-thrift-plugin。</a><br>　　首先新建一个maven项目，在pom.xml中加入如下配置。注意这里thrift采用的是0.9.3的版本，此时代码生成工具也必须为thrift-0.9.3.exe，两者必须匹配。thrift-0.9.3.exe已放置在项目的根目录下，文章最后会附有下载地址。<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="title">dependencies</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.apache.thrift<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>libthrift<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">version</span>&gt;</span>0.9.3<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">dependency</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.slf4j<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>slf4j-log4j12<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">version</span>&gt;</span>1.5.8<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">dependency</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">dependencies</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="title">build</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="title">plugins</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>maven-compiler-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">version</span>&gt;</span>3.1<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">source</span>&gt;</span>1.7<span class="tag">&lt;/<span class="title">source</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">target</span>&gt;</span>1.7<span class="tag">&lt;/<span class="title">target</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">encoding</span>&gt;</span>UTF-8<span class="tag">&lt;/<span class="title">encoding</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.apache.maven.plugins<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>maven-resources-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">version</span>&gt;</span>2.7<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">encoding</span>&gt;</span>UTF-8<span class="tag">&lt;/<span class="title">encoding</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line"></span><br><span class="line">        <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.apache.thrift.tools<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>thrift-maven-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">version</span>&gt;</span>0.1.13-SNAPSHOT<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!--thrift生成的java源码目录--&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">outputDirectory</span>&gt;</span>src/main/gen-java<span class="tag">&lt;/<span class="title">outputDirectory</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">thriftExecutable</span>&gt;</span>thrift-0.9.3.exe<span class="tag">&lt;/<span class="title">thriftExecutable</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!-- thrift 定义文件在thrift目录下--&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">thriftSourceRoot</span>&gt;</span>thrift<span class="tag">&lt;/<span class="title">thriftSourceRoot</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line">        <span class="comment">&lt;!-- 扩展源代码和资源文件目录 --&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="title">plugin</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">groupId</span>&gt;</span>org.codehaus.mojo<span class="tag">&lt;/<span class="title">groupId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">artifactId</span>&gt;</span>build-helper-maven-plugin<span class="tag">&lt;/<span class="title">artifactId</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">version</span>&gt;</span>1.7<span class="tag">&lt;/<span class="title">version</span>&gt;</span></span><br><span class="line">            <span class="tag">&lt;<span class="title">executions</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;<span class="title">execution</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">id</span>&gt;</span>add-source<span class="tag">&lt;/<span class="title">id</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">phase</span>&gt;</span>generate-sources<span class="tag">&lt;/<span class="title">phase</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">goals</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="title">goal</span>&gt;</span>add-source<span class="tag">&lt;/<span class="title">goal</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="title">goals</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;<span class="title">configuration</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;<span class="title">sources</span>&gt;</span></span><br><span class="line">                            <span class="comment">&lt;!-- 我们可以通过在这里添加多个source节点，来添加任意多个源文件夹 --&gt;</span></span><br><span class="line">                            <span class="tag">&lt;<span class="title">source</span>&gt;</span>src/main/gen-java<span class="tag">&lt;/<span class="title">source</span>&gt;</span></span><br><span class="line">                        <span class="tag">&lt;/<span class="title">sources</span>&gt;</span></span><br><span class="line">                    <span class="tag">&lt;/<span class="title">configuration</span>&gt;</span></span><br><span class="line">                <span class="tag">&lt;/<span class="title">execution</span>&gt;</span></span><br><span class="line">                <span class="comment">&lt;!--&lt;execution&gt;</span><br><span class="line">                    &lt;id&gt;add-resource&lt;/id&gt;</span><br><span class="line">                    &lt;phase&gt;generate-resources&lt;/phase&gt;</span><br><span class="line">                    &lt;goals&gt;</span><br><span class="line">                        &lt;goal&gt;add-resource&lt;/goal&gt;</span><br><span class="line">                    &lt;/goals&gt;</span><br><span class="line">                    &lt;configuration&gt;</span><br><span class="line">                        &lt;resources&gt;</span><br><span class="line">                            &amp;lt;!&amp;ndash; 我们可以通过在这里添加多个resource节点 &amp;ndash;&amp;gt;</span><br><span class="line">                            &lt;resource&gt;</span><br><span class="line">                                &lt;directory&gt;$&#123;basedir&#125;/src/multimodule/resources&lt;/directory&gt;</span><br><span class="line">                            &lt;/resource&gt;</span><br><span class="line">                        &lt;/resources&gt;</span><br><span class="line">                    &lt;/configuration&gt;</span><br><span class="line">                &lt;/execution&gt;--&gt;</span></span><br><span class="line">            <span class="tag">&lt;/<span class="title">executions</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;/<span class="title">plugin</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="title">plugins</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="title">build</span>&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>　　接着，我们定义三个thrift文件，分别为demoModel.thrift、demoService.thrift和demoService2.thrift。demoModel.thrift定义了一个User，另外两个Service，分别定义了HelloWorldService、HelloWorldService2，主要是为了演示Thrift对多接口服务的支持。<br><figure class="highlight thrift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">============demoModel.thrift=======</span><br><span class="line"><span class="keyword">namespace</span> java com.shc.thrift.demo.model</span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">User</span> </span>&#123;</span><br><span class="line">    <span class="number">1</span>: <span class="keyword">required</span> <span class="built_in">i32</span> type</span><br><span class="line">    <span class="number">2</span>: <span class="keyword">optional</span> <span class="built_in">string</span> name</span><br><span class="line">&#125;</span><br><span class="line">============demoService.thrift=======</span><br><span class="line">include <span class="string">"demoModel.thrift"</span></span><br><span class="line"><span class="keyword">namespace</span> java com.shc.thrift.demo.<span class="keyword">service</span></span><br><span class="line"><span class="class"><span class="keyword">service</span>  <span class="title">HelloWorldService</span> </span>&#123;</span><br><span class="line">  demoModel.User sayHello(<span class="number">1</span>:demoModel.User user)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">============demoService2.thrift=======</span><br><span class="line"><span class="keyword">namespace</span> java com.shc.thrift.demo.<span class="keyword">service</span></span><br><span class="line"><span class="class"><span class="keyword">service</span>  <span class="title">HelloWorldService2</span> </span>&#123;</span><br><span class="line">  <span class="built_in">string</span> sayHello(<span class="number">1</span>:<span class="built_in">string</span> name)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　执行thrift的maven插件，则可生成代码，这里不再做详述。下面我们实现上面定义的两个接口，实现类如下：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloWorldImpl</span> <span class="keyword">implements</span> <span class="title">HelloWorldService</span>.<span class="title">Iface</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> User <span class="title">sayHello</span><span class="params">(User user)</span> <span class="keyword">throws</span> TException </span>&#123;</span><br><span class="line">        user.setName(<span class="string">"新名称"</span>);</span><br><span class="line">        <span class="keyword">return</span> user;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloWorldImpl2</span> <span class="keyword">implements</span> <span class="title">HelloWorldService2</span>.<span class="title">Iface</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="annotation">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">sayHello</span><span class="params">(String name)</span> <span class="keyword">throws</span> TException </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"hello "</span> + name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　最后我们分别实现Server端和Client端代码，如下<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//服务端代码</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloServerDemo</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> Logger logger = LoggerFactory.getLogger(HelloServerDemo.class);</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> SERVER_PORT = <span class="number">8090</span>;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">startSingleServer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">"HelloWorld TSimpleServer start ...."</span>);</span><br><span class="line"></span><br><span class="line">            TProcessor tprocessor = <span class="keyword">new</span> HelloWorldService.Processor&lt;HelloWorldService.Iface&gt;(<span class="keyword">new</span> HelloWorldImpl());</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 简单的单线程服务模型，一般用于测试</span></span><br><span class="line">            TServerSocket serverTransport = <span class="keyword">new</span> TServerSocket(SERVER_PORT);</span><br><span class="line">            TServer.Args tArgs = <span class="keyword">new</span> TServer.Args(serverTransport);</span><br><span class="line">            tArgs.processor(tprocessor);</span><br><span class="line">            tArgs.protocolFactory(<span class="keyword">new</span> TBinaryProtocol.Factory());</span><br><span class="line">            <span class="comment">// tArgs.protocolFactory(new TCompactProtocol.Factory());</span></span><br><span class="line">            <span class="comment">// tArgs.protocolFactory(new TJSONProtocol.Factory());</span></span><br><span class="line">            TServer server = <span class="keyword">new</span> TSimpleServer(tArgs);</span><br><span class="line">            server.serve();</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            System.out.println(<span class="string">"Server start error!!!"</span>);</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">startMultiServer</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.out.println(<span class="string">"HelloWorld TSimpleServer start ...."</span>);</span><br><span class="line"></span><br><span class="line">            TMultiplexedProcessor processor = <span class="keyword">new</span> TMultiplexedProcessor();</span><br><span class="line">            processor.registerProcessor(<span class="string">"HelloWorldService"</span>, <span class="keyword">new</span> HelloWorldService.Processor&lt;HelloWorldService.Iface&gt;(<span class="keyword">new</span> HelloWorldImpl()));</span><br><span class="line">            processor.registerProcessor(<span class="string">"HelloWorldService2"</span>, <span class="keyword">new</span> HelloWorldService2.Processor&lt;HelloWorldService2.Iface&gt;(<span class="keyword">new</span> HelloWorldImpl2()));</span><br><span class="line"></span><br><span class="line">            <span class="comment">// 简单的单线程服务模型，一般用于测试</span></span><br><span class="line">            TServerSocket serverTransport = <span class="keyword">new</span> TServerSocket(SERVER_PORT);</span><br><span class="line">            TServer.Args tArgs = <span class="keyword">new</span> TServer.Args(serverTransport);</span><br><span class="line">            tArgs.processor(processor);</span><br><span class="line">            tArgs.protocolFactory(<span class="keyword">new</span> TBinaryProtocol.Factory());</span><br><span class="line">            <span class="comment">// tArgs.protocolFactory(new TCompactProtocol.Factory());</span></span><br><span class="line">            <span class="comment">// tArgs.protocolFactory(new TJSONProtocol.Factory());</span></span><br><span class="line">            TServer server = <span class="keyword">new</span> TSimpleServer(tArgs);</span><br><span class="line">            server.serve();</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">catch</span> (Exception e) &#123;</span><br><span class="line">            System.out.println(<span class="string">"Server start error!!!"</span>);</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        HelloServerDemo server = <span class="keyword">new</span> HelloServerDemo();</span><br><span class="line">        <span class="comment">//server.startSingleServer();</span></span><br><span class="line">        server.startMultiServer();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//客户端代码</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">HelloClientDemo</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String SERVER_IP = <span class="string">"localhost"</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> SERVER_PORT = <span class="number">8090</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> <span class="keyword">int</span> TIMEOUT = <span class="number">30000</span>;</span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">startClient</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        TTransport transport = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            transport = <span class="keyword">new</span> TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);</span><br><span class="line">            <span class="comment">// 协议要和服务端一致</span></span><br><span class="line">            TProtocol protocol = <span class="keyword">new</span> TBinaryProtocol(transport);</span><br><span class="line">            <span class="comment">// TProtocol protocol = new TCompactProtocol(transport);</span></span><br><span class="line">            <span class="comment">// TProtocol protocol = new TJSONProtocol(transport);</span></span><br><span class="line">            HelloWorldService.Client client = <span class="keyword">new</span> HelloWorldService.Client(protocol);</span><br><span class="line">            transport.open();</span><br><span class="line"></span><br><span class="line">            User user = <span class="keyword">new</span> User();</span><br><span class="line">            user.setName(<span class="string">"旧名称"</span>);</span><br><span class="line">            user.setType(<span class="number">1</span>);</span><br><span class="line">            <span class="comment">/*for(int i=0; i&lt;Integer.MAX_VALUE; i++)&#123;</span><br><span class="line">                user = client.sayHello(user);</span><br><span class="line">            &#125;*/</span></span><br><span class="line">            user = client.sayHello(user);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">            System.out.println(<span class="string">"Thrify client result =:  "</span> + user.getName());</span><br><span class="line">        &#125; <span class="keyword">catch</span> (TTransportException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (TException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="keyword">null</span> != transport) &#123;</span><br><span class="line">                transport.close();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">startMultiClient</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        TTransport transport = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            transport = <span class="keyword">new</span> TSocket(SERVER_IP, SERVER_PORT, TIMEOUT);</span><br><span class="line">            TProtocol protocol = <span class="keyword">new</span> TBinaryProtocol(transport);</span><br><span class="line"></span><br><span class="line">            TMultiplexedProtocol mp1 = <span class="keyword">new</span> TMultiplexedProtocol(protocol, <span class="string">"HelloWorldService"</span>);</span><br><span class="line">            HelloWorldService.Client service1 = <span class="keyword">new</span> HelloWorldService.Client(mp1);</span><br><span class="line"></span><br><span class="line">            TMultiplexedProtocol mp2 = <span class="keyword">new</span> TMultiplexedProtocol(protocol, <span class="string">"HelloWorldService2"</span>);</span><br><span class="line">            HelloWorldService2.Client service2 = <span class="keyword">new</span> HelloWorldService2.Client(mp2);</span><br><span class="line"></span><br><span class="line">            transport.open();</span><br><span class="line"></span><br><span class="line">            User user = <span class="keyword">new</span> User();</span><br><span class="line">            user.setType(<span class="number">1</span>);</span><br><span class="line">            user.setName(<span class="string">"老用户"</span>);</span><br><span class="line">            user = service1.sayHello(user);</span><br><span class="line">            System.out.println(<span class="string">"Thrify client result =:  "</span> + user.getName());</span><br><span class="line"></span><br><span class="line">            System.out.println(service2.sayHello(<span class="string">"张三"</span>));</span><br><span class="line"></span><br><span class="line">        &#125; <span class="keyword">catch</span> (TTransportException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (TException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125; <span class="keyword">finally</span> &#123;</span><br><span class="line">            <span class="keyword">if</span> (<span class="keyword">null</span> != transport) &#123;</span><br><span class="line">                transport.close();</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        HelloClientDemo client = <span class="keyword">new</span> HelloClientDemo();</span><br><span class="line">        <span class="comment">//client.startClient();</span></span><br><span class="line">        client.startMultiClient();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>　　运行代码我们即可看到预计的结果。我们可以看到，<strong>thrift除了提供交换数据的序列化/反序列化的能力外，还提供了多语言间RPC服务的框架</strong>。这点与很多流行的序列化/反序列化框架（如protocol buffer）不同。</p>
<h2 id="Transport"><a href="#Transport" class="headerlink" title="Transport"></a>Transport</h2><p>　　Transport层，顾名思义即数据传输层，它提供了一个简单的网络读写抽象。这使得thrift底层的transport从系统其它部分（如：序列化/反序列化）解耦。</p>
<h2 id="Protocol"><a href="#Protocol" class="headerlink" title="Protocol"></a>Protocol</h2><p>　　Protocol层，顾名思义即数据协议层，它定义了一种将内存中数据结构映射成可传输格式的机制。因此，Protocol的实现要给出编码机制并负责对数据进行序列化。目前thrift提供的协议主要有：TBinaryProtocol(二进制格式)、TCompactProtocol(压缩格式)、TJSONProtocol(JSON格式)和TSimpleJSONProtocol(提供JSON只写协议)等协议。</p>
<h2 id="Processor"><a href="#Processor" class="headerlink" title="Processor"></a>Processor</h2><p>　　Processor层，即处理层，它封装了从输入数据流中读数据和向输出数据流中写数据的操作，读写数据流用Protocol对象表示。上面的代码中主要体现在服务端的使用</p>
<h2 id="Server"><a href="#Server" class="headerlink" title="Server"></a>Server</h2><p>　　Server将以上所有特性集成在一起：<br>　　1. 创建一个transport对象<br>　　2. 为transport对象创建输入输出protocol<br>　　3. 基于输入输出protocol创建processor<br>　　4. 等待连接请求并将之交给processor处理</p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　可以看到，采用thrift时服务端编码基本步骤为：<br>　　1. 实现服务处理接口impl<br>　　2. 创建TProcessor<br>　　3. 创建TServerTransport<br>　　4. 创建TProtocol<br>　　5. 创建TServer<br>　　6. 启动Server<br>　　客户端编码基本步骤：<br>　　1. 创建Transport<br>　　2. 创建TProtocol<br>　　3. 基于TTransport和TProtocol创建 Client<br>　　4. 调用Client的相应方法<br>　　下一篇文章我们将深入分析thrift的源码，分析其实现机制和原理。 示例代码下载：<a href="/code/thrift-demo.rar">thrift-demo.rar</a>，thrift的maven插件：<a href="/code/maven-thrift-plugin.rar">maven-thrift-plugin.rar</a></p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://dongxicheng.org/search-engine/thrift-guide/" target="_blank" rel="external">http://dongxicheng.org/search-engine/thrift-guide/</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/rpc/5.RPC系列之Thrift入门/" data-id="cijzzpv3900291cfs0ws0jea1" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/rpc/">rpc</a></li></ul>

    </footer>
  </div>
  
</article>


  
    <article id="post-linux/4.Linux系列之内核优化" class="article article-type-post" itemscope itemprop="blogPost">
  <div class="article-meta">
    <a href="/2015/12/01/linux/4.Linux系列之内核优化/" class="article-date">
  <time datetime="2015-11-30T20:00:00.000Z" itemprop="datePublished">2015-12-01</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/linux/">linux</a>
  </div>

  </div>
  <div class="article-inner">
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/2015/12/01/linux/4.Linux系列之内核优化/">Linux系列四之内核优化</a>
    </h1>
  

      </header>
    
    <div class="article-entry" itemprop="articleBody">
      
        <h2 id="u80CC_u666F"><a href="#u80CC_u666F" class="headerlink" title="背景"></a>背景</h2><p>　　近期在做消息推送服务的性能测试，想知道单服务能支撑的最大连接数。在测试过程中发现了一些问题，再加上网上的资料都比较零散。为方便以后资料翻阅，在这篇文章中，我根据自己实际遇到的情况做一个简单的整理！</p>
<h2 id="u6D4B_u8BD5_u96BE_u70B9"><a href="#u6D4B_u8BD5_u96BE_u70B9" class="headerlink" title="测试难点"></a>测试难点</h2><p>　　根据自己实际遇到的情况，再加上网上的一些资料，列出几点大家需要注意的地方。实际不可能有那么多真机，所有都是通过客户端测试程序模拟大量终端的连接。<br>　　1. <strong>服务端限制</strong>：服务端需要给每个tcp连接分配一个端口，一个客户端ip能够分配的端口范围可以通过 cat /proc/sys/net/ipv4/ip_local_port_range 命令查看，但是多个客户端则可以有相同的端口(通过ip:port区别)。由于端口是16位整数，也就只能是0到 65535，而0到1023是预留端口，所以能分配的只是1024到65534，也就是64511个。也就是说，一台机器只能创建六万多个长连接。要达到百万连接，需要大概18台客户端。如果单个客户端发起连接太多，java应该会抛出异常java.net.NoRouteToHostException。注意：每个客户端连接，都会产生一个连接端口，该端口由服务端确定，给每个客户端。此处修改只在模拟并发时有用，真实上线时效果不大<br>　　2. <strong>客户端数量</strong>：（本人测试时机器足够，无此问题）上面预估了需要的客户端数量，如果不够该怎么办？客户机器绑定多张网卡或者虚拟网卡的基础上，给每个网卡分配一个IP地址，在起socket的时候指定socket client绑定的IP。<br>　　3. <strong>客户端程序</strong>：由于推送服务需要检测心跳信息，确认连接正常，所以测试程序需要发送心跳信息，并要能够连接是否正常。<br>　　4. kill掉服务，可能导致运行客户端的虚拟机不能ssh登陆，通过vnc连接，查看客户端虚拟机CPU，dmesg中存在Out of socket memory这样的错误信息，原因：服务端和客户端之间存在4万连接，服务进程挂掉后客户端机器收到大量FIN包导致网络相关内存溢出，而客户端机器上存在一个使用curl的定时任务，网络内存溢出引发其某个bug，进而引发CPU跑满。因此调大net.ipv4.tcp_mem配置，注意该参数的单位是页，而不是字节（ 本人没遇到过，在此只是记录一下）</p>
<h2 id="u6700_u5927_u6587_u4EF6_u63CF_u8FF0_u7B26"><a href="#u6700_u5927_u6587_u4EF6_u63CF_u8FF0_u7B26" class="headerlink" title="最大文件描述符"></a>最大文件描述符</h2><p>　　客户端连接越来越多时会出现异常：java.net.SocketException: Too many open files，此时需要修改服务器的最大句柄数。注意：open files是针对单一进程的限制，我们可以通过启动多个服务来解决（不建议，无法得到推送服务的性能极限）。最大句柄数不是越大越好，系统限制的最大值为：1048576（在2.6.25内核之前有个 宏定义，定义了这个值的最大值为1024*1024，在2.6.25内核及其之后，这个值是可以通过/proc/sys/fs /nr_open来设置），设置方式如下：<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 查看系统对单进程的open files最大数限制：1048576</span></span><br><span class="line">cat /proc/sys/fs/nr_open</span><br><span class="line"></span><br><span class="line"><span class="comment">#永久修改open files</span></span><br><span class="line">vi /etc/security/limits.conf</span><br><span class="line"><span class="comment"># hard limit不能大于/proc/sys/fs/nr_open</span></span><br><span class="line"><span class="comment">#* hard nofile 1048576  </span></span><br><span class="line"><span class="comment">#* soft nofile 1048576</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">#修改单个文件打开最大句柄数，临时修改open files，重启后失效</span></span><br><span class="line"><span class="comment">#注意不能超过上面的1048576，通过ulimit -a 查看所有参数的说明</span></span><br><span class="line"><span class="comment">#也不能超过/etc/security/limits.conf中的配置</span></span><br><span class="line"><span class="built_in">ulimit</span> -n <span class="number">1048576</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#注意soft limit不能大于hard limit</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#同时设置soft limit和hard limit</span></span><br><span class="line"><span class="built_in">ulimit</span> -n <span class="number">1800000</span></span><br><span class="line"><span class="comment">#设置soft limit，必须小于hard limit</span></span><br><span class="line"><span class="built_in">ulimit</span> -Sn <span class="number">1600000</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#ulimit -n默认查看的是soft limit</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#查看hard limit</span></span><br><span class="line"><span class="built_in">ulimit</span> -Hn</span><br><span class="line"></span><br><span class="line"><span class="comment">#注销用户重新登录，执行ulimit -a 检查修改是否生效</span></span><br><span class="line"><span class="comment">#也可以通过如下命令查看指定进程的最大文件句柄数（需将pid改为实际的进程号）</span></span><br><span class="line">cat /proc/pid/limits</span><br><span class="line"></span><br><span class="line"><span class="comment">#在/etc/sysctl.conf中配置系统所有进程打开的文件数，修改参数fs.file-max即可</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#查看当前系统使用的打开文件描述符数情况</span></span><br><span class="line">cat /proc/sys/fs/file-nr</span><br><span class="line"><span class="number">5664</span>        <span class="number">0</span>        <span class="number">186405</span></span><br><span class="line"><span class="comment">#第一个数表示当前系统已分配使用的打开文件描述符数</span></span><br><span class="line"><span class="comment">#第二个数为分配后已释放的（目前已不再使用）</span></span><br><span class="line"><span class="comment">#第三个数等于file-max。</span></span><br></pre></td></tr></table></figure></p>
<h2 id="u5E38_u7528_u547D_u4EE4"><a href="#u5E38_u7528_u547D_u4EE4" class="headerlink" title="常用命令"></a>常用命令</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#确认最终建立的tcp连接数，包括estab、closed、timewait等状态的</span></span><br><span class="line"><span class="comment">#-s, --summary        show socket usage summary</span></span><br><span class="line">ss <span class="operator">-s</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#系统日志信息，压力测试时可以看到很多socket相关的信息</span></span><br><span class="line"><span class="comment">#将信息输出到指定的文件中</span></span><br><span class="line">dmesg &gt; /home/log.data</span><br></pre></td></tr></table></figure>
<h2 id="/etc/sysctl-conf"><a href="#/etc/sysctl-conf" class="headerlink" title="/etc/sysctl.conf"></a>/etc/sysctl.conf</h2><p>　　高负载系统，修改配置文件/etc/sysctl.conf 中参数，调整网络参数。然后执行 <strong>/sbin/sysctl -p</strong> 使配置立即生效<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line">net.ipv4.tcp_syncookies = <span class="number">1</span></span><br><span class="line"><span class="comment">#开启SYN Cookies。当出现SYN等待队列溢出时，启用cookies来处理，可防范少量SYN攻击，默认为0，表示关闭</span></span><br><span class="line"></span><br><span class="line">net.ipv4.tcp_rmem = <span class="number">4096</span> <span class="number">4096</span> <span class="number">16777216</span>  </span><br><span class="line"><span class="comment">#配置读缓冲的大小，三个值，第一个是这个读缓冲的最小值，第三个是最大值，中间的是默认值。</span></span><br><span class="line"><span class="comment">#可以在程序中修改读缓冲的大小，但是不能超过最小与最大。</span></span><br><span class="line"></span><br><span class="line">net.ipv4.tcp_wmem = <span class="number">4096</span> <span class="number">4096</span> <span class="number">16777216</span></span><br><span class="line"><span class="comment">#配置写缓冲的大小。</span></span><br><span class="line"><span class="comment">#读缓冲与写缓冲在大小，直接影响到socket在内核中内存的占用。</span></span><br><span class="line"></span><br><span class="line">net.ipv4.tcp_mem = <span class="number">786432</span> <span class="number">2097152</span> <span class="number">3145728</span>  </span><br><span class="line"><span class="comment">#配置tcp的内存大小，其单位是页，而不是字节。</span></span><br><span class="line"><span class="comment">#当超过第二个值时，TCP进入 pressure模式，此时TCP尝试稳定其内存的使用</span></span><br><span class="line"><span class="comment">#当小于第一个值时，就退出pressure模式。</span></span><br><span class="line"><span class="comment">#当内存占用超过第三个值时，TCP就拒绝分配 socket了</span></span><br><span class="line"><span class="comment">#查看dmesg，会打出很多的日志“TCP: too many of orphaned sockets”。</span></span><br><span class="line"></span><br><span class="line">net.ipv4.tcp_max_orphans = <span class="number">131072</span>  </span><br><span class="line"><span class="comment">#孤儿socket最大数量</span></span><br><span class="line"><span class="comment">#系统所能处理不属于任何进程的 socket数量，当需要快速建立大量连接时，就要关注下这个值。</span></span><br><span class="line"><span class="comment">#当不属于任何进程的socket的数量大于这个值时，dmesg就会看 到”too many of orphaned sockets”。</span></span><br><span class="line"></span><br><span class="line">net.ipv4.tcp_tw_reuse = <span class="number">1</span>  </span><br><span class="line"><span class="comment">#开启重用。允许将TIME-WAIT sockets重新用于新的TCP连接，默认为0，表示关闭；</span></span><br><span class="line"></span><br><span class="line">net.ipv4.tcp_tw_recycle = <span class="number">1</span>  </span><br><span class="line"><span class="comment">#开启TCP连接中TIME-WAIT sockets的快速回收，默认为0，表示关闭。</span></span><br><span class="line"></span><br><span class="line">net.ipv4.tcp_max_tw_buckets = <span class="number">5000</span></span><br><span class="line"><span class="comment">#系统同时保持TIME_WAIT套接字的最大数量，如果超过这个数字，TIME_WAIT套接字将立刻被清除并打印警告信息。</span></span><br><span class="line"><span class="comment">#默认为 180000，改为5000。</span></span><br><span class="line"><span class="comment">#对于Apache、Nginx等服务器，上几行的参数可以很好地减少TIME_WAIT套接字数量，</span></span><br><span class="line"><span class="comment">#对于Squid，效果不大。此项参数可以控制TIME_WAIT套接字的最大数量，避免Squid服务器被大量的TIME_WAIT套接字拖死。</span></span><br><span class="line"></span><br><span class="line">net.ipv4.tcp_fin_timeout = <span class="number">30</span>  </span><br><span class="line"><span class="comment">#如果套接字由本端要求关闭，这个参数决定了它保持在FIN-WAIT-2状态的时间。</span></span><br><span class="line"></span><br><span class="line">net.ipv4.tcp_keepalive_time = <span class="number">1200</span>  </span><br><span class="line"><span class="comment">#当keepalive起用的时候，**TCP发送keepalive消息的频度**。缺省是2小时，改为20分钟。</span></span><br><span class="line"></span><br><span class="line">net.ipv4.ip_<span class="built_in">local</span>_port_range = <span class="number">1024</span> <span class="number">65000</span>  </span><br><span class="line"><span class="comment">#用于向外连接的端口范围。缺省情况下很小：32768到61000，改为1024到65000。</span></span><br><span class="line"></span><br><span class="line">net.ipv4.tcp_max_syn_backlog = <span class="number">8192</span>  </span><br><span class="line"><span class="comment">#SYN队列的长度，默认为1024，加大队列长度为8192，可以容纳更多等待连接的网络连接数。</span></span><br><span class="line"></span><br><span class="line">fs.file-max</span><br><span class="line"><span class="comment">#针对整个系统而非单个进程的文件句柄的最大数量（所有进程的总数），文件句柄设置表示在linux系统中可以打开的文件数量。</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#如果高负载系统使用了netfilter/iptables，调整以下参数</span></span><br><span class="line">net.ipv4.ip_conntrack_max = <span class="number">655360</span>  </span><br><span class="line"><span class="comment">#在内核内存中netfilter可以同时处理的“任务”（连接跟踪条目）</span></span><br><span class="line">net.ipv4.netfilter.ip_conntrack_tcp_timeout_established = <span class="number">180</span>  </span><br><span class="line"><span class="comment">#跟踪的连接超时结束时间</span></span><br></pre></td></tr></table></figure></p>
<h2 id="/proc_u865A_u62DF_u6587_u4EF6_u7CFB_u7EDF"><a href="#/proc_u865A_u62DF_u6587_u4EF6_u7CFB_u7EDF" class="headerlink" title="/proc虚拟文件系统"></a>/proc虚拟文件系统</h2><p>　　/proc/sys目录下存放着大多数的内核参数，并且设计成可以<strong>在系统运行的同时进行更改</strong>，不需要重新引导系统, 不过重新启动机器后会失效，可以通过更改/proc/sys中内核参数对应的文件 /etc/sysctl.conf 的内核参数来永久更改。<br>　　下面我们以打开内核的 ip转发功能为例说明在系统运行时修改内核参数的两种方法。IP转发是指允许系统对来源和目的地都不是本机的数据包通过网络，RedHat默认屏蔽此功能，在 需要用本机作为路由器、NAT等情况下需要开启此功能。<br>　　方法一：直接修改内核参数ip_forward对应在/proc下的文件/proc/sys/net/ipv4/ip_forward内容，<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#查看ip_forward文件内容，该文件默认值0是禁止ip转发，1是开启ip转发功能。</span></span><br><span class="line">cat /proc/sys/net/ipv4/ip_forward</span><br><span class="line"><span class="comment">#修改为开启状态，如果系统重启后则又恢复为默认值0</span></span><br><span class="line"><span class="built_in">echo</span> <span class="number">1</span> &gt; /proc/sys/net/ipv4/ip_forward</span><br></pre></td></tr></table></figure></p>
<p>　　方法二．修改/etc/sysctl.conf文件，每次系统启动时初始化脚本/etc/rc.d/rc.sysinit会读取/etc/sysctl.conf文件的内容，所以修改后每次系统启动时都会开启ip转发功能<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#修改/etc/sysctl.conf</span></span><br><span class="line">vi /etc/sysctl.conf</span><br><span class="line"><span class="comment">#将ip_forward值改为1，重启仍然生效</span></span><br><span class="line">net.ipv4.ip_forward = <span class="number">1</span></span><br><span class="line"><span class="comment">#使修改马上生效</span></span><br><span class="line">sysctl –p</span><br></pre></td></tr></table></figure></p>
<p>　　将/proc/sys中的文件转换成 sysctl 中的变量依据下面两个简单的规则：<br>　　1．去掉前面部分/proc/sys<br>　　2．将文件名中的斜杠变为点。</p>
<p>　　这两条规则可以将/proc/sys中的任一文件名转换成sysctl中的变量名。例如：<br>　　/proc/sys/net/ipv4/ip_forward -&gt; net.ipv4.ip_forward<br>　　/proc/sys/kernel/hostname -&gt; kernel.hostname</p>
<p>　　可以使用命令<strong>sysctl –a</strong>查询所有可修改的变量名，下面例举几个简单的内核参数：<br>　　1．/proc/sys/kernel/shmmax 该文件指定内核所允许的最大共享内存段的大小。<br>　　2．/proc/sys/kernel/threads-max 该文件指定内核所能使用的线程的最大数目。<br>　　3．/proc/sys/kernel/hostname 该文件允许您配置网络主机名。<br>　　4．/proc/sys/kernel/domainname 该文件允许您配置网络域名</p>
<h2 id="u603B_u7ED3"><a href="#u603B_u7ED3" class="headerlink" title="总结"></a>总结</h2><p>　　1. 所有进程打开的文件描述符数不能超过/proc/sys/fs/file-max<br>　　2. 单个进程打开的文件描述符数不能超过user limit中nofile的soft limit<br>　　3. nofile的soft limit不能超过其hard limit<br>　　4. nofile的hard limit不能超过/proc/sys/fs/nr_open<br>　　在测试的过程中，需要根据dmesg打出系统的信息不断调整服务端/etc/sysctl.conf中的配置。</p>
<h2 id="u53C2_u8003_u8D44_u6599"><a href="#u53C2_u8003_u8D44_u6599" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="http://qa.blog.163.com/blog/static/190147002201342115957410/" target="_blank" rel="external">http://qa.blog.163.com/blog/static/190147002201342115957410/</a><br><a href="http://blog.csdn.net/superchanon/article/details/13303705" target="_blank" rel="external">http://blog.csdn.net/superchanon/article/details/13303705</a><br><a href="http://f.dataguru.cn/article-7442-1.html" target="_blank" rel="external">http://f.dataguru.cn/article-7442-1.html</a></p>

      
    </div>
    <footer class="article-footer">
      <a data-url="http://yoursite.com/2015/12/01/linux/4.Linux系列之内核优化/" data-id="cijzzpvcl00bi1cfsuo10twdq" class="article-share-link">Share</a>
      
      
  <ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/linux/">linux</a></li></ul>

    </footer>
  </div>
  
</article>


  
  
    <nav id="page-nav">
      <a class="extend prev" rel="prev" href="/page/13/">&laquo; Prev</a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/12/">12</a><a class="page-number" href="/page/13/">13</a><span class="page-number current">14</span><a class="page-number" href="/page/15/">15</a><a class="extend next" rel="next" href="/page/15/">Next &raquo;</a>
    </nav>
  
</section>
        
          <aside id="sidebar">
  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Categories</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/cache/">cache</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/database/">database</a><span class="category-list-count">13</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/docker/">docker</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gis/">gis</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/go/">go</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/gradle/">gradle</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/groovy/">groovy</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hadoop/">hadoop</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/java/">java</a><span class="category-list-count">18</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/linux/">linux</a><span class="category-list-count">4</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/log/">log</a><span class="category-list-count">11</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mongodb/">mongodb</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mq/">mq</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/mybatis/">mybatis</a><span class="category-list-count">9</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/netty/">netty</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nginx/">nginx</a><span class="category-list-count">3</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nio/">nio</a><span class="category-list-count">19</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/nodejs/">nodejs</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/redis/">redis</a><span class="category-list-count">6</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/rpc/">rpc</a><span class="category-list-count">14</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/spring/">spring</a><span class="category-list-count">5</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/tomcat/">tomcat</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/zookeeper/">zookeeper</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/杂项/">杂项</a><span class="category-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tags</h3>
    <div class="widget">
      <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/aop/">aop</a><span class="tag-list-count">8</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/aspectj/">aspectj</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/cache/">cache</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/classloader/">classloader</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/common-loggings/">common-loggings</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/commonjs/">commonjs</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/database/">database</a><span class="tag-list-count">10</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/docker/">docker</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/dubbo/">dubbo</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/fastdfs/">fastdfs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gclib/">gclib</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/geohash/">geohash</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gis/">gis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/go/">go</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/gradle/">gradle</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/groovy/">groovy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hadoop/">hadoop</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hessisan/">hessisan</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/java/">java</a><span class="tag-list-count">48</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/javassist/">javassist</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/kafka/">kafka</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/linux/">linux</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log/">log</a><span class="tag-list-count">11</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/log4j/">log4j</a><span class="tag-list-count">4</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/logback/">logback</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/map/">map</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/memecached/">memecached</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mina/">mina</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mongodb/">mongodb</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mq/">mq</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mqtt/">mqtt</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/mybatis/">mybatis</a><span class="tag-list-count">9</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/netty/">netty</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nginx/">nginx</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nio/">nio</a><span class="tag-list-count">5</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nodejs/">nodejs</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/postgresql/">postgresql</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/protobuf/">protobuf</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/proxy/">proxy</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/push/">push</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rabbitmq/">rabbitmq</a><span class="tag-list-count">3</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/">redis</a><span class="tag-list-count">6</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/rpc/">rpc</a><span class="tag-list-count">14</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sitemesh/">sitemesh</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/sld/">sld</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/slf4j/">slf4j</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/socket/">socket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spatialite-for-android/">spatialite for android</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spi/">spi</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/spring/">spring</a><span class="tag-list-count">13</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/tomcat/">tomcat</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/transaction/">transaction</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/web/">web</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/xSocket/">xSocket</a><span class="tag-list-count">7</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zbus/">zbus</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/zookeeper/">zookeeper</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/数据结构/">数据结构</a><span class="tag-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Tag Cloud</h3>
    <div class="widget tagcloud">
      <a href="/tags/aop/" style="font-size: 15.38px;">aop</a> <a href="/tags/aspectj/" style="font-size: 11.54px;">aspectj</a> <a href="/tags/cache/" style="font-size: 11.54px;">cache</a> <a href="/tags/classloader/" style="font-size: 10px;">classloader</a> <a href="/tags/common-loggings/" style="font-size: 10px;">common-loggings</a> <a href="/tags/commonjs/" style="font-size: 12.31px;">commonjs</a> <a href="/tags/database/" style="font-size: 16.92px;">database</a> <a href="/tags/docker/" style="font-size: 13.85px;">docker</a> <a href="/tags/dubbo/" style="font-size: 10px;">dubbo</a> <a href="/tags/fastdfs/" style="font-size: 10px;">fastdfs</a> <a href="/tags/gclib/" style="font-size: 10.77px;">gclib</a> <a href="/tags/geohash/" style="font-size: 10px;">geohash</a> <a href="/tags/gis/" style="font-size: 10px;">gis</a> <a href="/tags/git/" style="font-size: 10.77px;">git</a> <a href="/tags/go/" style="font-size: 10px;">go</a> <a href="/tags/gradle/" style="font-size: 10px;">gradle</a> <a href="/tags/groovy/" style="font-size: 10px;">groovy</a> <a href="/tags/hadoop/" style="font-size: 10px;">hadoop</a> <a href="/tags/hessisan/" style="font-size: 11.54px;">hessisan</a> <a href="/tags/java/" style="font-size: 20px;">java</a> <a href="/tags/javassist/" style="font-size: 10px;">javassist</a> <a href="/tags/kafka/" style="font-size: 11.54px;">kafka</a> <a href="/tags/linux/" style="font-size: 12.31px;">linux</a> <a href="/tags/log/" style="font-size: 17.69px;">log</a> <a href="/tags/log4j/" style="font-size: 12.31px;">log4j</a> <a href="/tags/logback/" style="font-size: 13.08px;">logback</a> <a href="/tags/map/" style="font-size: 10px;">map</a> <a href="/tags/memecached/" style="font-size: 10.77px;">memecached</a> <a href="/tags/mina/" style="font-size: 13.08px;">mina</a> <a href="/tags/mongodb/" style="font-size: 19.23px;">mongodb</a> <a href="/tags/mq/" style="font-size: 13.85px;">mq</a> <a href="/tags/mqtt/" style="font-size: 10.77px;">mqtt</a> <a href="/tags/mybatis/" style="font-size: 16.15px;">mybatis</a> <a href="/tags/netty/" style="font-size: 10px;">netty</a> <a href="/tags/nginx/" style="font-size: 11.54px;">nginx</a> <a href="/tags/nio/" style="font-size: 13.08px;">nio</a> <a href="/tags/nodejs/" style="font-size: 10px;">nodejs</a> <a href="/tags/postgresql/" style="font-size: 10.77px;">postgresql</a> <a href="/tags/protobuf/" style="font-size: 10px;">protobuf</a> <a href="/tags/proxy/" style="font-size: 10px;">proxy</a> <a href="/tags/push/" style="font-size: 10px;">push</a> <a href="/tags/rabbitmq/" style="font-size: 11.54px;">rabbitmq</a> <a href="/tags/redis/" style="font-size: 13.85px;">redis</a> <a href="/tags/rpc/" style="font-size: 19.23px;">rpc</a> <a href="/tags/sitemesh/" style="font-size: 10px;">sitemesh</a> <a href="/tags/sld/" style="font-size: 10px;">sld</a> <a href="/tags/slf4j/" style="font-size: 10px;">slf4j</a> <a href="/tags/socket/" style="font-size: 14.62px;">socket</a> <a href="/tags/spatialite-for-android/" style="font-size: 10px;">spatialite for android</a> <a href="/tags/spi/" style="font-size: 10px;">spi</a> <a href="/tags/spring/" style="font-size: 18.46px;">spring</a> <a href="/tags/tomcat/" style="font-size: 10.77px;">tomcat</a> <a href="/tags/transaction/" style="font-size: 10px;">transaction</a> <a href="/tags/web/" style="font-size: 10px;">web</a> <a href="/tags/xSocket/" style="font-size: 14.62px;">xSocket</a> <a href="/tags/zbus/" style="font-size: 10px;">zbus</a> <a href="/tags/zookeeper/" style="font-size: 10.77px;">zookeeper</a> <a href="/tags/数据结构/" style="font-size: 10.77px;">数据结构</a>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Archives</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/01/">January 2016</a><span class="archive-list-count">67</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/12/">December 2015</a><span class="archive-list-count">81</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2015/11/">November 2015</a><span class="archive-list-count">2</span></li></ul>
    </div>
  </div>

  
    
  <div class="widget-wrap">
    <h3 class="widget-title">Recents</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2016/01/30/资料/">(no title)</a>
          </li>
        
          <li>
            <a href="/2016/01/30/java/13.Classloader系列一/">ClassLoader系列一</a>
          </li>
        
          <li>
            <a href="/2016/01/29/hadoop/1.hadoop系列之源码编译/">hadoop系列一之源码编译</a>
          </li>
        
          <li>
            <a href="/2016/01/29/go/1.GO系列之入门/">Go系列一之入门</a>
          </li>
        
          <li>
            <a href="/2016/01/28/tomcat/2.tomcat性能优化/">tomcat性能优化</a>
          </li>
        
      </ul>
    </div>
  </div>

  
</aside>
        
      </div>
      <footer id="footer">
  
  <div class="outer">
    <div id="footer-info" class="inner">
      &copy; 2016 John Doe<br>
      Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>
    </div>
  </div>
</footer>
    </div>
    <nav id="mobile-nav">
  
    <a href="/" class="mobile-nav-link">Home</a>
  
    <a href="/archives" class="mobile-nav-link">Archives</a>
  
</nav>
    


<script src="http://libs.baidu.com/jquery/2.0.3/jquery.min.js"></script>


  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css">
  <script src="/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>


<script src="/js/script.js" type="text/javascript"></script>

  </div>
</body>
</html>